1 /* 2 * Metafile driver initialisation functions 3 * 4 * Copyright 1996 Alexandre Julliard 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #include <stdarg.h> 22 #include <string.h> 23 24 #include "windef.h" 25 #include "winbase.h" 26 #include "winnls.h" 27 #include "gdi_private.h" 28 #include "mfdrv/metafiledrv.h" 29 #include "wine/debug.h" 30 31 WINE_DEFAULT_DEBUG_CHANNEL(metafile); 32 33 static BOOL MFDRV_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev ); 34 static BOOL MFDRV_DeleteDC( PHYSDEV dev ); 35 36 37 /********************************************************************** 38 * MFDRV_ExtEscape 39 */ 40 static INT MFDRV_ExtEscape( PHYSDEV dev, INT nEscape, INT cbInput, LPCVOID in_data, 41 INT cbOutput, LPVOID out_data ) 42 { 43 METARECORD *mr; 44 DWORD len; 45 INT ret; 46 47 if (cbOutput) return 0; /* escapes that require output cannot work in metafiles */ 48 49 len = sizeof(*mr) + sizeof(WORD) + ((cbInput + 1) & ~1); 50 mr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); 51 mr->rdSize = len / 2; 52 mr->rdFunction = META_ESCAPE; 53 mr->rdParm[0] = nEscape; 54 mr->rdParm[1] = cbInput; 55 memcpy(&(mr->rdParm[2]), in_data, cbInput); 56 ret = MFDRV_WriteRecord( dev, mr, len); 57 HeapFree(GetProcessHeap(), 0, mr); 58 return ret; 59 } 60 61 62 /****************************************************************** 63 * MFDRV_GetBoundsRect 64 */ 65 static UINT MFDRV_GetBoundsRect( PHYSDEV dev, RECT *rect, UINT flags ) 66 { 67 return 0; 68 } 69 70 71 /****************************************************************** 72 * MFDRV_SetBoundsRect 73 */ 74 static UINT MFDRV_SetBoundsRect( PHYSDEV dev, RECT *rect, UINT flags ) 75 { 76 return 0; 77 } 78 79 80 /****************************************************************** 81 * MFDRV_GetDeviceCaps 82 * 83 *A very simple implementation that returns DT_METAFILE 84 */ 85 static INT MFDRV_GetDeviceCaps(PHYSDEV dev, INT cap) 86 { 87 switch(cap) 88 { 89 case TECHNOLOGY: 90 return DT_METAFILE; 91 case TEXTCAPS: 92 return 0; 93 default: 94 TRACE(" unsupported capability %d, will return 0\n", cap ); 95 } 96 return 0; 97 } 98 99 100 static const struct gdi_dc_funcs MFDRV_Funcs = 101 { 102 NULL, /* pAbortDoc */ 103 MFDRV_AbortPath, /* pAbortPath */ 104 NULL, /* pAlphaBlend */ 105 NULL, /* pAngleArc */ 106 MFDRV_Arc, /* pArc */ 107 NULL, /* pArcTo */ 108 MFDRV_BeginPath, /* pBeginPath */ 109 NULL, /* pBlendImage */ 110 MFDRV_Chord, /* pChord */ 111 MFDRV_CloseFigure, /* pCloseFigure */ 112 MFDRV_CreateCompatibleDC, /* pCreateCompatibleDC */ 113 NULL, /* pCreateDC */ 114 MFDRV_DeleteDC, /* pDeleteDC */ 115 MFDRV_DeleteObject, /* pDeleteObject */ 116 NULL, /* pDeviceCapabilities */ 117 MFDRV_Ellipse, /* pEllipse */ 118 NULL, /* pEndDoc */ 119 NULL, /* pEndPage */ 120 MFDRV_EndPath, /* pEndPath */ 121 NULL, /* pEnumFonts */ 122 NULL, /* pEnumICMProfiles */ 123 MFDRV_ExcludeClipRect, /* pExcludeClipRect */ 124 NULL, /* pExtDeviceMode */ 125 MFDRV_ExtEscape, /* pExtEscape */ 126 MFDRV_ExtFloodFill, /* pExtFloodFill */ 127 MFDRV_ExtSelectClipRgn, /* pExtSelectClipRgn */ 128 MFDRV_ExtTextOut, /* pExtTextOut */ 129 MFDRV_FillPath, /* pFillPath */ 130 MFDRV_FillRgn, /* pFillRgn */ 131 MFDRV_FlattenPath, /* pFlattenPath */ 132 NULL, /* pFontIsLinked */ 133 MFDRV_FrameRgn, /* pFrameRgn */ 134 NULL, /* pGdiComment */ 135 MFDRV_GetBoundsRect, /* pGetBoundsRect */ 136 NULL, /* pGetCharABCWidths */ 137 NULL, /* pGetCharABCWidthsI */ 138 NULL, /* pGetCharWidth */ 139 MFDRV_GetDeviceCaps, /* pGetDeviceCaps */ 140 NULL, /* pGetDeviceGammaRamp */ 141 NULL, /* pGetFontData */ 142 NULL, /* pGetFontRealizationInfo */ 143 NULL, /* pGetFontUnicodeRanges */ 144 NULL, /* pGetGlyphIndices */ 145 NULL, /* pGetGlyphOutline */ 146 NULL, /* pGetICMProfile */ 147 NULL, /* pGetImage */ 148 NULL, /* pGetKerningPairs */ 149 NULL, /* pGetNearestColor */ 150 NULL, /* pGetOutlineTextMetrics */ 151 NULL, /* pGetPixel */ 152 NULL, /* pGetSystemPaletteEntries */ 153 NULL, /* pGetTextCharsetInfo */ 154 NULL, /* pGetTextExtentExPoint */ 155 NULL, /* pGetTextExtentExPointI */ 156 NULL, /* pGetTextFace */ 157 NULL, /* pGetTextMetrics */ 158 NULL, /* pGradientFill */ 159 MFDRV_IntersectClipRect, /* pIntersectClipRect */ 160 MFDRV_InvertRgn, /* pInvertRgn */ 161 MFDRV_LineTo, /* pLineTo */ 162 NULL, /* pModifyWorldTransform */ 163 MFDRV_MoveTo, /* pMoveTo */ 164 MFDRV_OffsetClipRgn, /* pOffsetClipRgn */ 165 MFDRV_OffsetViewportOrgEx, /* pOffsetViewportOrgEx */ 166 MFDRV_OffsetWindowOrgEx, /* pOffsetWindowOrgEx */ 167 MFDRV_PaintRgn, /* pPaintRgn */ 168 MFDRV_PatBlt, /* pPatBlt */ 169 MFDRV_Pie, /* pPie */ 170 MFDRV_PolyBezier, /* pPolyBezier */ 171 MFDRV_PolyBezierTo, /* pPolyBezierTo */ 172 NULL, /* pPolyDraw */ 173 MFDRV_PolyPolygon, /* pPolyPolygon */ 174 NULL, /* pPolyPolyline */ 175 MFDRV_Polygon, /* pPolygon */ 176 MFDRV_Polyline, /* pPolyline */ 177 NULL, /* pPolylineTo */ 178 NULL, /* pPutImage */ 179 NULL, /* pRealizeDefaultPalette */ 180 MFDRV_RealizePalette, /* pRealizePalette */ 181 MFDRV_Rectangle, /* pRectangle */ 182 NULL, /* pResetDC */ 183 MFDRV_RestoreDC, /* pRestoreDC */ 184 MFDRV_RoundRect, /* pRoundRect */ 185 MFDRV_SaveDC, /* pSaveDC */ 186 MFDRV_ScaleViewportExtEx, /* pScaleViewportExtEx */ 187 MFDRV_ScaleWindowExtEx, /* pScaleWindowExtEx */ 188 MFDRV_SelectBitmap, /* pSelectBitmap */ 189 MFDRV_SelectBrush, /* pSelectBrush */ 190 MFDRV_SelectClipPath, /* pSelectClipPath */ 191 MFDRV_SelectFont, /* pSelectFont */ 192 MFDRV_SelectPalette, /* pSelectPalette */ 193 MFDRV_SelectPen, /* pSelectPen */ 194 NULL, /* pSetArcDirection */ 195 MFDRV_SetBkColor, /* pSetBkColor */ 196 MFDRV_SetBkMode, /* pSetBkMode */ 197 MFDRV_SetBoundsRect, /* pSetBoundsRect */ 198 MFDRV_SetDCBrushColor, /* pSetDCBrushColor*/ 199 MFDRV_SetDCPenColor, /* pSetDCPenColor*/ 200 MFDRV_SetDIBitsToDevice, /* pSetDIBitsToDevice */ 201 NULL, /* pSetDeviceClipping */ 202 NULL, /* pSetDeviceGammaRamp */ 203 NULL, /* pSetLayout */ 204 MFDRV_SetMapMode, /* pSetMapMode */ 205 MFDRV_SetMapperFlags, /* pSetMapperFlags */ 206 MFDRV_SetPixel, /* pSetPixel */ 207 MFDRV_SetPolyFillMode, /* pSetPolyFillMode */ 208 MFDRV_SetROP2, /* pSetROP2 */ 209 MFDRV_SetRelAbs, /* pSetRelAbs */ 210 MFDRV_SetStretchBltMode, /* pSetStretchBltMode */ 211 MFDRV_SetTextAlign, /* pSetTextAlign */ 212 MFDRV_SetTextCharacterExtra, /* pSetTextCharacterExtra */ 213 MFDRV_SetTextColor, /* pSetTextColor */ 214 MFDRV_SetTextJustification, /* pSetTextJustification */ 215 MFDRV_SetViewportExtEx, /* pSetViewportExtEx */ 216 MFDRV_SetViewportOrgEx, /* pSetViewportOrgEx */ 217 MFDRV_SetWindowExtEx, /* pSetWindowExtEx */ 218 MFDRV_SetWindowOrgEx, /* pSetWindowOrgEx */ 219 NULL, /* pSetWorldTransform */ 220 NULL, /* pStartDoc */ 221 NULL, /* pStartPage */ 222 MFDRV_StretchBlt, /* pStretchBlt */ 223 MFDRV_StretchDIBits, /* pStretchDIBits */ 224 MFDRV_StrokeAndFillPath, /* pStrokeAndFillPath */ 225 MFDRV_StrokePath, /* pStrokePath */ 226 NULL, /* pUnrealizePalette */ 227 MFDRV_WidenPath, /* pWidenPath */ 228 NULL, /* wine_get_wgl_driver */ 229 GDI_PRIORITY_GRAPHICS_DRV /* priority */ 230 }; 231 232 233 234 /********************************************************************** 235 * MFDRV_AllocMetaFile 236 */ 237 static DC *MFDRV_AllocMetaFile(void) 238 { 239 DC *dc; 240 METAFILEDRV_PDEVICE *physDev; 241 242 if (!(dc = alloc_dc_ptr( OBJ_METADC ))) return NULL; 243 244 physDev = HeapAlloc(GetProcessHeap(),0,sizeof(*physDev)); 245 if (!physDev) 246 { 247 free_dc_ptr( dc ); 248 return NULL; 249 } 250 if (!(physDev->mh = HeapAlloc( GetProcessHeap(), 0, sizeof(*physDev->mh) ))) 251 { 252 HeapFree( GetProcessHeap(), 0, physDev ); 253 free_dc_ptr( dc ); 254 return NULL; 255 } 256 257 push_dc_driver( &dc->physDev, &physDev->dev, &MFDRV_Funcs ); 258 259 physDev->handles = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, HANDLE_LIST_INC * sizeof(physDev->handles[0])); 260 physDev->handles_size = HANDLE_LIST_INC; 261 physDev->cur_handles = 0; 262 263 physDev->hFile = 0; 264 265 physDev->mh->mtHeaderSize = sizeof(METAHEADER) / sizeof(WORD); 266 physDev->mh->mtVersion = 0x0300; 267 physDev->mh->mtSize = physDev->mh->mtHeaderSize; 268 physDev->mh->mtNoObjects = 0; 269 physDev->mh->mtMaxRecord = 0; 270 physDev->mh->mtNoParameters = 0; 271 272 SetVirtualResolution( physDev->dev.hdc, 0, 0, 0, 0); 273 274 return dc; 275 } 276 277 278 /********************************************************************** 279 * MFDRV_CreateCompatibleDC 280 */ 281 static BOOL MFDRV_CreateCompatibleDC( PHYSDEV orig, PHYSDEV *pdev ) 282 { 283 /* not supported on metafile DCs */ 284 return FALSE; 285 } 286 287 288 /********************************************************************** 289 * MFDRV_DeleteDC 290 */ 291 static BOOL MFDRV_DeleteDC( PHYSDEV dev ) 292 { 293 METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev; 294 DWORD index; 295 296 HeapFree( GetProcessHeap(), 0, physDev->mh ); 297 for(index = 0; index < physDev->handles_size; index++) 298 if(physDev->handles[index]) 299 GDI_hdc_not_using_object(physDev->handles[index], dev->hdc); 300 HeapFree( GetProcessHeap(), 0, physDev->handles ); 301 HeapFree( GetProcessHeap(), 0, physDev ); 302 return TRUE; 303 } 304 305 306 /********************************************************************** 307 * CreateMetaFileW (GDI32.@) 308 * 309 * Create a new DC and associate it with a metafile. Pass a filename 310 * to create a disk-based metafile, NULL to create a memory metafile. 311 * 312 * PARAMS 313 * filename [I] Filename of disk metafile 314 * 315 * RETURNS 316 * A handle to the metafile DC if successful, NULL on failure. 317 */ 318 HDC WINAPI CreateMetaFileW( LPCWSTR filename ) 319 { 320 HDC ret; 321 DC *dc; 322 METAFILEDRV_PDEVICE *physDev; 323 HANDLE hFile; 324 DWORD bytes_written; 325 326 TRACE("%s\n", debugstr_w(filename) ); 327 328 if (!(dc = MFDRV_AllocMetaFile())) return 0; 329 physDev = (METAFILEDRV_PDEVICE *)dc->physDev; 330 331 if (filename) /* disk based metafile */ 332 { 333 physDev->mh->mtType = METAFILE_DISK; 334 if ((hFile = CreateFileW(filename, GENERIC_WRITE, 0, NULL, 335 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) { 336 free_dc_ptr( dc ); 337 return 0; 338 } 339 if (!WriteFile( hFile, physDev->mh, sizeof(*physDev->mh), 340 &bytes_written, NULL )) { 341 free_dc_ptr( dc ); 342 CloseHandle (hFile ); 343 return 0; 344 } 345 physDev->hFile = hFile; 346 347 /* Grow METAHEADER to include filename */ 348 physDev->mh = MF_CreateMetaHeaderDisk(physDev->mh, filename, TRUE); 349 } 350 else /* memory based metafile */ 351 physDev->mh->mtType = METAFILE_MEMORY; 352 353 TRACE("returning %p\n", physDev->dev.hdc); 354 ret = physDev->dev.hdc; 355 release_dc_ptr( dc ); 356 return ret; 357 } 358 359 /********************************************************************** 360 * CreateMetaFileA (GDI32.@) 361 * 362 * See CreateMetaFileW. 363 */ 364 HDC WINAPI CreateMetaFileA(LPCSTR filename) 365 { 366 LPWSTR filenameW; 367 DWORD len; 368 HDC hReturnDC; 369 370 if (!filename) return CreateMetaFileW(NULL); 371 372 len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 ); 373 filenameW = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) ); 374 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len ); 375 376 hReturnDC = CreateMetaFileW(filenameW); 377 378 HeapFree( GetProcessHeap(), 0, filenameW ); 379 380 return hReturnDC; 381 } 382 383 384 /********************************************************************** 385 * MFDRV_CloseMetaFile 386 */ 387 static DC *MFDRV_CloseMetaFile( HDC hdc ) 388 { 389 DC *dc; 390 METAFILEDRV_PDEVICE *physDev; 391 DWORD bytes_written; 392 393 TRACE("(%p)\n", hdc ); 394 395 if (!(dc = get_dc_ptr( hdc ))) return NULL; 396 if (GetObjectType( hdc ) != OBJ_METADC) 397 { 398 release_dc_ptr( dc ); 399 return NULL; 400 } 401 if (dc->refcount != 1) 402 { 403 FIXME( "not deleting busy DC %p refcount %u\n", hdc, dc->refcount ); 404 release_dc_ptr( dc ); 405 return NULL; 406 } 407 physDev = (METAFILEDRV_PDEVICE *)dc->physDev; 408 409 /* Construct the end of metafile record - this is documented 410 * in SDK Knowledgebase Q99334. 411 */ 412 413 if (!MFDRV_MetaParam0(dc->physDev, META_EOF)) 414 { 415 free_dc_ptr( dc ); 416 return 0; 417 } 418 419 if (physDev->mh->mtType == METAFILE_DISK) /* disk based metafile */ 420 { 421 if (SetFilePointer(physDev->hFile, 0, NULL, FILE_BEGIN) != 0) { 422 free_dc_ptr( dc ); 423 return 0; 424 } 425 426 physDev->mh->mtType = METAFILE_MEMORY; /* This is what windows does */ 427 if (!WriteFile(physDev->hFile, physDev->mh, sizeof(*physDev->mh), 428 &bytes_written, NULL)) { 429 free_dc_ptr( dc ); 430 return 0; 431 } 432 CloseHandle(physDev->hFile); 433 physDev->mh->mtType = METAFILE_DISK; 434 } 435 436 return dc; 437 } 438 439 /****************************************************************** 440 * CloseMetaFile (GDI32.@) 441 * 442 * Stop recording graphics operations in metafile associated with 443 * hdc and retrieve metafile. 444 * 445 * PARAMS 446 * hdc [I] Metafile DC to close 447 * 448 * RETURNS 449 * Handle of newly created metafile on success, NULL on failure. 450 */ 451 HMETAFILE WINAPI CloseMetaFile(HDC hdc) 452 { 453 HMETAFILE hmf; 454 METAFILEDRV_PDEVICE *physDev; 455 DC *dc = MFDRV_CloseMetaFile(hdc); 456 if (!dc) return 0; 457 physDev = (METAFILEDRV_PDEVICE *)dc->physDev; 458 459 /* Now allocate a global handle for the metafile */ 460 461 hmf = MF_Create_HMETAFILE( physDev->mh ); 462 463 physDev->mh = NULL; /* So it won't be deleted */ 464 free_dc_ptr( dc ); 465 return hmf; 466 } 467 468 469 /****************************************************************** 470 * MFDRV_WriteRecord 471 * 472 * Warning: this function can change the pointer to the metafile header. 473 */ 474 BOOL MFDRV_WriteRecord( PHYSDEV dev, METARECORD *mr, DWORD rlen) 475 { 476 DWORD len, size; 477 METAHEADER *mh; 478 METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev; 479 480 switch(physDev->mh->mtType) 481 { 482 case METAFILE_MEMORY: 483 len = physDev->mh->mtSize * 2 + rlen; 484 /* reallocate memory if needed */ 485 size = HeapSize( GetProcessHeap(), 0, physDev->mh ); 486 if (len > size) 487 { 488 /*expand size*/ 489 size += size / 2 + rlen; 490 mh = HeapReAlloc( GetProcessHeap(), 0, physDev->mh, size); 491 if (!mh) return FALSE; 492 physDev->mh = mh; 493 TRACE("Reallocated metafile: new size is %d\n",size); 494 } 495 memcpy((WORD *)physDev->mh + physDev->mh->mtSize, mr, rlen); 496 break; 497 case METAFILE_DISK: 498 TRACE("Writing record to disk\n"); 499 if (!WriteFile(physDev->hFile, mr, rlen, NULL, NULL)) 500 return FALSE; 501 break; 502 default: 503 ERR("Unknown metafile type %d\n", physDev->mh->mtType ); 504 return FALSE; 505 } 506 507 physDev->mh->mtSize += rlen / 2; 508 physDev->mh->mtMaxRecord = max(physDev->mh->mtMaxRecord, rlen / 2); 509 return TRUE; 510 } 511 512 513 /****************************************************************** 514 * MFDRV_MetaParam0 515 */ 516 517 BOOL MFDRV_MetaParam0(PHYSDEV dev, short func) 518 { 519 char buffer[8]; 520 METARECORD *mr = (METARECORD *)&buffer; 521 522 mr->rdSize = 3; 523 mr->rdFunction = func; 524 return MFDRV_WriteRecord( dev, mr, mr->rdSize * 2); 525 } 526 527 528 /****************************************************************** 529 * MFDRV_MetaParam1 530 */ 531 BOOL MFDRV_MetaParam1(PHYSDEV dev, short func, short param1) 532 { 533 char buffer[8]; 534 METARECORD *mr = (METARECORD *)&buffer; 535 WORD *params = mr->rdParm; 536 537 mr->rdSize = 4; 538 mr->rdFunction = func; 539 params[0] = param1; 540 return MFDRV_WriteRecord( dev, mr, mr->rdSize * 2); 541 } 542 543 544 /****************************************************************** 545 * MFDRV_MetaParam2 546 */ 547 BOOL MFDRV_MetaParam2(PHYSDEV dev, short func, short param1, short param2) 548 { 549 char buffer[10]; 550 METARECORD *mr = (METARECORD *)&buffer; 551 WORD *params = mr->rdParm; 552 553 mr->rdSize = 5; 554 mr->rdFunction = func; 555 params[0] = param2; 556 params[1] = param1; 557 return MFDRV_WriteRecord( dev, mr, mr->rdSize * 2); 558 } 559 560 561 /****************************************************************** 562 * MFDRV_MetaParam4 563 */ 564 565 BOOL MFDRV_MetaParam4(PHYSDEV dev, short func, short param1, short param2, 566 short param3, short param4) 567 { 568 char buffer[14]; 569 METARECORD *mr = (METARECORD *)&buffer; 570 WORD *params = mr->rdParm; 571 572 mr->rdSize = 7; 573 mr->rdFunction = func; 574 params[0] = param4; 575 params[1] = param3; 576 params[2] = param2; 577 params[3] = param1; 578 return MFDRV_WriteRecord( dev, mr, mr->rdSize * 2); 579 } 580 581 582 /****************************************************************** 583 * MFDRV_MetaParam6 584 */ 585 586 BOOL MFDRV_MetaParam6(PHYSDEV dev, short func, short param1, short param2, 587 short param3, short param4, short param5, short param6) 588 { 589 char buffer[18]; 590 METARECORD *mr = (METARECORD *)&buffer; 591 WORD *params = mr->rdParm; 592 593 mr->rdSize = 9; 594 mr->rdFunction = func; 595 params[0] = param6; 596 params[1] = param5; 597 params[2] = param4; 598 params[3] = param3; 599 params[4] = param2; 600 params[5] = param1; 601 return MFDRV_WriteRecord( dev, mr, mr->rdSize * 2); 602 } 603 604 605 /****************************************************************** 606 * MFDRV_MetaParam8 607 */ 608 BOOL MFDRV_MetaParam8(PHYSDEV dev, short func, short param1, short param2, 609 short param3, short param4, short param5, 610 short param6, short param7, short param8) 611 { 612 char buffer[22]; 613 METARECORD *mr = (METARECORD *)&buffer; 614 WORD *params = mr->rdParm; 615 616 mr->rdSize = 11; 617 mr->rdFunction = func; 618 params[0] = param8; 619 params[1] = param7; 620 params[2] = param6; 621 params[3] = param5; 622 params[4] = param4; 623 params[5] = param3; 624 params[6] = param2; 625 params[7] = param1; 626 return MFDRV_WriteRecord( dev, mr, mr->rdSize * 2); 627 } 628