:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / subsys / win32k / objects / text.c
1
2
3 #undef WIN32_LEAN_AND_MEAN
4 #include <windows.h>
5 #include <ddk/ntddk.h>
6 #include <win32k/dc.h>
7 #include <win32k/text.h>
8 #include <win32k/kapi.h>
9 #include <freetype/freetype.h>
10
11 #include "../eng/handle.h"
12
13 // #define NDEBUG
14 #include <win32k/debug1.h>
15
16 FT_Library  library;
17
18 typedef struct _FONTTABLE {
19   HFONT hFont;
20   LPCWSTR FaceName;
21 } FONTTABLE, *PFONTTABLE;
22
23 FONTTABLE FontTable[256];
24 INT FontsLoaded = 0;
25
26 BOOL InitFontSupport()
27 {
28   ULONG error;
29
30   error = FT_Init_FreeType(&library);
31   if(error)
32   {
33     return FALSE;
34   }
35
36   W32kAddFontResource(L"\\SystemRoot\\media\\fonts\\helb____.ttf");
37   W32kAddFontResource(L"\\SystemRoot\\media\\fonts\\timr____.ttf");
38
39   DbgPrint("All fonts loaded\n");
40
41   return TRUE;
42 }
43
44 int
45 STDCALL
46 W32kAddFontResource(LPCWSTR  Filename)
47 {
48   HFONT NewFont;
49   PFONTOBJ FontObj;
50   PFONTGDI FontGDI;
51   UNICODE_STRING uFileName;
52   NTSTATUS Status;
53   HANDLE FileHandle;
54   OBJECT_ATTRIBUTES ObjectAttributes;
55   FILE_STANDARD_INFORMATION FileStdInfo;
56   PVOID buffer;
57   ULONG size;
58   INT error;
59   FT_Face face;
60   ANSI_STRING StringA;
61   UNICODE_STRING StringU;
62   IO_STATUS_BLOCK Iosb;
63
64   NewFont = (HFONT)CreateGDIHandle(sizeof( FONTGDI ), sizeof( FONTOBJ ));
65   FontObj = (PFONTOBJ) AccessUserObject( NewFont );
66   FontGDI = (PFONTGDI) AccessInternalObject( NewFont );
67
68   RtlCreateUnicodeString(&uFileName, (LPWSTR)Filename);
69
70   //  Open the Module
71   InitializeObjectAttributes(&ObjectAttributes, &uFileName, 0, NULL, NULL);
72
73   Status = NtOpenFile(&FileHandle, FILE_ALL_ACCESS, &ObjectAttributes, &Iosb, 0, 0);
74
75   if (!NT_SUCCESS(Status))
76   {
77     DbgPrint("Could not open module file: %S\n", Filename);
78     return 0;
79   }
80
81   //  Get the size of the file
82   Status = NtQueryInformationFile(FileHandle, &Iosb, &FileStdInfo, sizeof(FileStdInfo), FileStandardInformation);
83   if (!NT_SUCCESS(Status))
84   {
85     DbgPrint("Could not get file size\n");
86     return 0;
87   }
88
89   //  Allocate nonpageable memory for driver
90   size = FileStdInfo.EndOfFile.u.LowPart;
91   buffer = ExAllocatePool(NonPagedPool, size);
92
93   if (buffer == NULL)
94   {
95     DbgPrint("could not allocate memory for module");
96     return 0;
97   }
98
99   //  Load driver into memory chunk
100   Status = NtReadFile(FileHandle, 0, 0, 0, &Iosb, buffer, FileStdInfo.EndOfFile.u.LowPart, 0, 0);
101   if (!NT_SUCCESS(Status))
102   {
103     DbgPrint("could not read module file into memory");
104     ExFreePool(buffer);
105     return 0;
106   }
107
108   NtClose(FileHandle);
109
110   error = FT_New_Memory_Face(library, buffer, size, 0, &face);
111   if (error == FT_Err_Unknown_File_Format)
112   {
113     DbgPrint("Unknown font file format\n");
114     return 0;
115   }
116   else if (error)
117   {
118     DbgPrint("Error reading font file (error code: %u)\n", error); // 48
119     return 0;
120   }
121
122   // FontGDI->Filename = Filename; perform strcpy
123   FontGDI->face = face;
124
125   // FIXME: Complete text metrics
126   FontGDI->TextMetric.tmAscent = face->size->metrics.ascender; // units above baseline
127   FontGDI->TextMetric.tmDescent = face->size->metrics.descender; // units below baseline
128   FontGDI->TextMetric.tmHeight = FontGDI->TextMetric.tmAscent + FontGDI->TextMetric.tmDescent;
129
130   DbgPrint("Family name: %s\n", face->family_name);
131   DbgPrint("Style name: %s\n", face->style_name);
132   DbgPrint("Num glyphs: %u\n", face->num_glyphs);
133
134   // Add this font resource to the font table
135   FontTable[FontsLoaded].hFont = NewFont;
136
137   RtlInitAnsiString(&StringA, (LPSTR)face->family_name);
138   RtlAnsiStringToUnicodeString(&StringU, &StringA, TRUE);
139   FontTable[FontsLoaded].FaceName = ExAllocatePool(NonPagedPool, (StringU.Length + 1) * 2);
140   wcscpy((LPWSTR)FontTable[FontsLoaded].FaceName, StringU.Buffer);
141   RtlFreeUnicodeString(&StringU);
142
143   FontsLoaded++;
144
145   return 1;
146 }
147
148 HFONT
149 STDCALL
150 W32kCreateFont(int  Height,
151                       int  Width,
152                       int  Escapement,
153                       int  Orientation,
154                       int  Weight,
155                       DWORD  Italic,
156                       DWORD  Underline,
157                       DWORD  StrikeOut,
158                       DWORD  CharSet,
159                       DWORD  OutputPrecision,
160                       DWORD  ClipPrecision,
161                       DWORD  Quality,
162                       DWORD  PitchAndFamily,
163                       LPCWSTR  Face)
164 {
165   LOGFONT logfont;
166
167   logfont.lfHeight = Height;
168   logfont.lfWidth = Width;
169   logfont.lfEscapement = Escapement;
170   logfont.lfOrientation = Orientation;
171   logfont.lfWeight = Weight;
172   logfont.lfItalic = Italic;
173   logfont.lfUnderline = Underline;
174   logfont.lfStrikeOut = StrikeOut;
175   logfont.lfCharSet = CharSet;
176   logfont.lfOutPrecision = OutputPrecision;
177   logfont.lfClipPrecision = ClipPrecision;
178   logfont.lfQuality = Quality;
179   logfont.lfPitchAndFamily = PitchAndFamily;
180
181   if(Face)
182     memcpy(logfont.lfFaceName, Face, sizeof(logfont.lfFaceName));
183   else
184     logfont.lfFaceName[0] = '\0';
185
186   return W32kCreateFontIndirect(&logfont);
187 }
188
189 HFONT
190 STDCALL
191 W32kCreateFontIndirect(CONST LPLOGFONT  lf)
192 {
193   HFONT hFont = 0;
194   PTEXTOBJ fontPtr;
195
196   if (lf)
197   {
198     if(hFont = TEXTOBJ_AllocText())
199     {
200           fontPtr = TEXTOBJ_LockText( hFont );
201           ASSERT( fontPtr );  //I want to know when this happens
202           if( fontPtr ){
203         memcpy(&fontPtr->logfont, lf, sizeof(LOGFONT));
204
205         if (lf->lfEscapement != lf->lfOrientation) {
206           /* this should really depend on whether GM_ADVANCED is set */
207           fontPtr->logfont.lfOrientation = fontPtr->logfont.lfEscapement;
208         }
209                 TEXTOBJ_UnlockText( hFont );
210           }
211     }
212   }
213
214   return hFont;
215 }
216
217 BOOL
218 STDCALL
219 W32kCreateScalableFontResource(DWORD  Hidden,
220                                      LPCWSTR  FontRes,
221                                      LPCWSTR  FontFile,
222                                      LPCWSTR  CurrentPath)
223 {
224   UNIMPLEMENTED;
225 }
226
227 int
228 STDCALL
229 W32kEnumFontFamilies(HDC  hDC,
230                           LPCWSTR  Family,
231                           FONTENUMPROC  EnumFontFamProc,
232                           LPARAM  lParam)
233 {
234   UNIMPLEMENTED;
235 }
236
237 int
238 STDCALL
239 W32kEnumFontFamiliesEx(HDC  hDC,
240                             LPLOGFONT  Logfont,
241                             FONTENUMPROC  EnumFontFamExProc,
242                             LPARAM  lParam,
243                             DWORD  Flags)
244 {
245   UNIMPLEMENTED;
246 }
247
248 int
249 STDCALL
250 W32kEnumFonts(HDC  hDC,
251                    LPCWSTR FaceName,
252                    FONTENUMPROC  FontFunc,
253                    LPARAM  lParam)
254 {
255   UNIMPLEMENTED;
256 }
257
258 BOOL
259 STDCALL
260 W32kExtTextOut(HDC  hDC,
261                      int  X,
262                      int  Y,
263                      UINT  Options,
264                      CONST LPRECT  rc,
265                      LPCWSTR  String,
266                      UINT  Count,
267                      CONST LPINT  Dx)
268 {
269   UNIMPLEMENTED;
270 }
271
272 BOOL
273 STDCALL
274 W32kGetAspectRatioFilterEx(HDC  hDC,
275                                  LPSIZE  AspectRatio)
276 {
277   UNIMPLEMENTED;
278 }
279
280 BOOL
281 STDCALL
282 W32kGetCharABCWidths(HDC  hDC,
283                            UINT  FirstChar,
284                            UINT  LastChar,
285                            LPABC  abc)
286 {
287   UNIMPLEMENTED;
288 }
289
290 BOOL
291 STDCALL
292 W32kGetCharABCWidthsFloat(HDC  hDC,
293                                 UINT  FirstChar,
294                                 UINT  LastChar,
295                                 LPABCFLOAT  abcF)
296 {
297   UNIMPLEMENTED;
298 }
299
300 DWORD
301 STDCALL
302 W32kGetCharacterPlacement(HDC  hDC,
303                                  LPCWSTR  String,
304                                  int  Count,
305                                  int  MaxExtent,
306                                  LPGCP_RESULTS  Results,
307                                  DWORD  Flags)
308 {
309   UNIMPLEMENTED;
310 }
311
312 BOOL
313 STDCALL
314 W32kGetCharWidth(HDC  hDC,
315                        UINT  FirstChar,
316                        UINT  LastChar,
317                        LPINT  Buffer)
318 {
319   UNIMPLEMENTED;
320 }
321
322 BOOL
323 STDCALL
324 W32kGetCharWidth32(HDC  hDC,
325                          UINT  FirstChar,
326                          UINT  LastChar,
327                          LPINT  Buffer)
328 {
329   UNIMPLEMENTED;
330 }
331
332 BOOL
333 STDCALL
334 W32kGetCharWidthFloat(HDC  hDC,
335                             UINT  FirstChar,
336                             UINT  LastChar,
337                             PFLOAT  Buffer)
338 {
339   UNIMPLEMENTED;
340 }
341
342 DWORD
343 STDCALL
344 W32kGetFontLanguageInfo(HDC  hDC)
345 {
346   UNIMPLEMENTED;
347 }
348
349 DWORD
350 STDCALL
351 W32kGetGlyphOutline(HDC  hDC,
352                            UINT  Char,
353                            UINT  Format,
354                            LPGLYPHMETRICS  gm,
355                            DWORD  Bufsize,
356                            LPVOID  Buffer,
357                            CONST LPMAT2 mat2)
358 {
359   UNIMPLEMENTED;
360
361
362 }
363
364 DWORD
365 STDCALL
366 W32kGetKerningPairs(HDC  hDC,
367                            DWORD  NumPairs,
368                            LPKERNINGPAIR  krnpair)
369 {
370   UNIMPLEMENTED;
371 }
372
373 UINT
374 STDCALL
375 W32kGetOutlineTextMetrics(HDC  hDC,
376                                 UINT  Data,
377                                 LPOUTLINETEXTMETRIC  otm)
378 {
379   UNIMPLEMENTED;
380 }
381
382 BOOL
383 STDCALL
384 W32kGetRasterizerCaps(LPRASTERIZER_STATUS  rs,
385                             UINT  Size)
386 {
387   UNIMPLEMENTED;
388 }
389
390 UINT
391 STDCALL
392 W32kGetTextCharset(HDC  hDC)
393 {
394   UNIMPLEMENTED;
395 }
396
397 UINT
398 STDCALL
399 W32kGetTextCharsetInfo(HDC  hDC,
400                              LPFONTSIGNATURE  Sig,
401                              DWORD  Flags)
402 {
403   UNIMPLEMENTED;
404 }
405
406 BOOL
407 STDCALL
408 W32kGetTextExtentExPoint(HDC  hDC,
409                                LPCWSTR String,
410                                int  Count,
411                                int  MaxExtent,
412                                LPINT  Fit,
413                                LPINT  Dx,
414                                LPSIZE  Size)
415 {
416   UNIMPLEMENTED;
417 }
418
419 BOOL
420 STDCALL
421 W32kGetTextExtentPoint(HDC  hDC,
422                              LPCWSTR  String,
423                              int  Count,
424                              LPSIZE  Size)
425 {
426   PDC dc = (PDC)AccessUserObject(hDC);
427   PFONTGDI FontGDI;
428   FT_Face face;
429   FT_GlyphSlot glyph;
430   INT error, pitch, glyph_index, i;
431   ULONG TotalWidth = 0, MaxHeight = 0, CurrentChar = 0, SpaceBetweenChars = 5;
432
433   FontGDI = (PFONTGDI)AccessInternalObject(dc->w.hFont);
434
435   for(i=0; i<Count; i++)
436   {
437     glyph_index = FT_Get_Char_Index(face, *String);
438     error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
439     if(error) DbgPrint("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
440     glyph = face->glyph;
441
442     if (glyph->format == ft_glyph_format_outline)
443     {
444       error = FT_Render_Glyph(glyph, ft_render_mode_mono);
445       if(error) DbgPrint("WARNING: Failed to render glyph!\n");
446       pitch = glyph->bitmap.pitch;
447     } else {
448       pitch = glyph->bitmap.width;
449     }
450
451     TotalWidth += pitch-1;
452     if((glyph->bitmap.rows-1) > MaxHeight) MaxHeight = glyph->bitmap.rows-1;
453
454     CurrentChar++;
455
456     if(CurrentChar < Size->cx) TotalWidth += SpaceBetweenChars;
457     String++;
458   }
459
460   Size->cx = TotalWidth;
461   Size->cy = MaxHeight;
462 }
463
464 BOOL
465 STDCALL
466 W32kGetTextExtentPoint32(HDC  hDC,
467                                LPCWSTR  String,
468                                int  Count,
469                                LPSIZE  Size)
470 {
471   UNIMPLEMENTED;
472 }
473
474 int
475 STDCALL
476 W32kGetTextFace(HDC  hDC,
477                      int  Count,
478                      LPWSTR  FaceName)
479 {
480   UNIMPLEMENTED;
481 }
482
483 BOOL
484 STDCALL
485 W32kGetTextMetrics(HDC  hDC,
486                          LPTEXTMETRIC  tm)
487 {
488   PDC dc = (PDC)AccessUserObject(hDC);
489   PFONTGDI FontGDI;
490
491   FontGDI = (PFONTGDI)AccessInternalObject(dc->w.hFont);
492   memcpy(tm, &FontGDI->TextMetric, sizeof(TEXTMETRIC));
493
494   return TRUE;
495 }
496
497 BOOL
498 STDCALL
499 W32kPolyTextOut(HDC  hDC,
500                       CONST LPPOLYTEXT  txt,
501                       int  Count)
502 {
503   UNIMPLEMENTED;
504 }
505
506 BOOL
507 STDCALL
508 W32kRemoveFontResource(LPCWSTR  FileName)
509 {
510   UNIMPLEMENTED;
511 }
512
513 DWORD
514 STDCALL
515 W32kSetMapperFlags(HDC  hDC,
516                           DWORD  Flag)
517 {
518   UNIMPLEMENTED;
519 }
520
521 UINT
522 STDCALL
523 W32kSetTextAlign(HDC  hDC,
524                        UINT  Mode)
525 {
526   UINT prevAlign;
527   DC *dc;
528
529   dc = DC_HandleToPtr(hDC);
530   if (!dc)
531     {
532       return  0;
533     }
534   prevAlign = dc->w.textAlign;
535   dc->w.textAlign = Mode;
536   DC_ReleasePtr( hDC );
537   return  prevAlign;
538 }
539
540 COLORREF
541 STDCALL
542 W32kSetTextColor(HDC hDC,
543                  COLORREF color)
544 {
545   COLORREF  oldColor;
546   PDC  dc = DC_HandleToPtr(hDC);
547
548   if (!dc)
549   {
550     return 0x80000000;
551   }
552
553   oldColor = dc->w.textColor;
554   dc->w.textColor = color;
555   DC_ReleasePtr( hDC );
556   return  oldColor;
557 }
558
559 BOOL
560 STDCALL
561 W32kSetTextJustification(HDC  hDC,
562                                int  BreakExtra,
563                                int  BreakCount)
564 {
565   UNIMPLEMENTED;
566 }
567
568 BOOL
569 STDCALL
570 W32kTextOut(HDC  hDC,
571                   int  XStart,
572                   int  YStart,
573                   LPCWSTR  String,
574                   int  Count)
575 {
576   // Fixme: Call EngTextOut, which does the real work (calling DrvTextOut where appropriate)
577
578   DC *dc = DC_HandleToPtr(hDC);
579   SURFOBJ *SurfObj = (SURFOBJ*)AccessUserObject(dc->Surface);
580   int error, glyph_index, n, load_flags = FT_LOAD_RENDER, i, j, sx, sy, scc;
581   FT_Face face;
582   FT_GlyphSlot glyph;
583   ULONG TextLeft, TextTop, SpaceBetweenChars = 2, pitch, previous;
584   FT_Bool use_kerning;
585   RECTL DestRect, MaskRect;
586   POINTL SourcePoint, BrushOrigin;
587   HBRUSH hBrush = NULL;
588   PBRUSHOBJ Brush = NULL;
589   HBITMAP HSourceGlyph;
590   PSURFOBJ SourceGlyphSurf;
591   SIZEL bitSize;
592   FT_CharMap found = 0, charmap;
593   INT yoff;
594   HFONT hFont = 0;
595   PFONTOBJ FontObj;
596   PFONTGDI FontGDI;
597   PTEXTOBJ TextObj;
598   PPALGDI PalDestGDI;
599   PXLATEOBJ XlateObj;
600
601   if( !dc )
602         return FALSE;
603
604   XStart += dc->w.DCOrgX;
605   YStart += dc->w.DCOrgY;
606   TextLeft = XStart;
607   TextTop = YStart;
608
609   TextObj = TEXTOBJ_LockText(dc->w.hFont);
610
611   for(i=0; i<FontsLoaded; i++)
612   {
613     if(wcscmp(FontTable[i].FaceName, (LPSTR)TextObj->logfont.lfFaceName) == 0)
614      hFont = FontTable[i].hFont;
615   }
616
617   if(hFont == 0)
618   {
619     DbgPrint("Specified font %s is not loaded\n", TextObj->logfont.lfFaceName);
620         goto fail;
621   }
622
623   FontObj = (PFONTOBJ)AccessUserObject(hFont);
624   FontGDI = (PFONTGDI)AccessInternalObject(hFont);
625   face = FontGDI->face;
626
627   if (face->charmap == NULL)
628   {
629     DbgPrint("WARNING: No charmap selected!\n");
630     DbgPrint("This font face has %d charmaps\n", face->num_charmaps);
631
632     for (n = 0; n < face->num_charmaps; n++)
633     {
634       charmap = face->charmaps[n];
635       DbgPrint("found charmap encoding: %u\n", charmap->encoding);
636       if (charmap->encoding != 0)
637       {
638         found = charmap;
639         break;
640       }
641     }
642     if (!found) DbgPrint("WARNING: Could not find desired charmap!\n");
643     error = FT_Set_Charmap(face, found);
644     if (error) DbgPrint("WARNING: Could not set the charmap!\n");
645   }
646
647   error = FT_Set_Pixel_Sizes(face, TextObj->logfont.lfHeight, TextObj->logfont.lfWidth);
648   if(error) {
649     DbgPrint("Error in setting pixel sizes: %u\n", error);
650         goto fail;
651   }
652
653   // Create the brush
654   PalDestGDI = (PPALGDI)AccessInternalObject(dc->w.hPalette);
655   XlateObj = (PXLATEOBJ)EngCreateXlate(PalDestGDI->Mode, PAL_RGB, dc->w.hPalette, NULL);
656   hBrush = W32kCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor));
657   Brush = BRUSHOBJ_LockBrush(hBrush);
658   EngDeleteXlate(XlateObj);
659
660   SourcePoint.x = 0;
661   SourcePoint.y = 0;
662   MaskRect.left = 0;
663   MaskRect.top = 0;
664   BrushOrigin.x = 0;
665   BrushOrigin.y = 0;
666
667   // Determine the yoff from the dc's w.textAlign
668   if (dc->w.textAlign & TA_BASELINE) {
669     yoff = 0;
670   }
671   else
672   if (dc->w.textAlign & TA_BOTTOM) {
673     yoff = -face->size->metrics.descender / 64;
674   }
675   else { // TA_TOP
676     yoff = face->size->metrics.ascender / 64;
677   }
678
679   use_kerning = FT_HAS_KERNING(face);
680   previous = 0;
681
682   for(i=0; i<Count; i++)
683   {
684     glyph_index = FT_Get_Char_Index(face, *String);
685     error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
686     if(error) {
687       DbgPrint("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
688       goto fail;
689     }
690     glyph = face->glyph;
691
692     // retrieve kerning distance and move pen position
693     if (use_kerning && previous && glyph_index)
694     {
695       FT_Vector delta;
696       FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
697       TextLeft += delta.x >> 6;
698     }
699
700     if (glyph->format == ft_glyph_format_outline)
701     {
702       error = FT_Render_Glyph(glyph, ft_render_mode_mono);
703       if(error) {
704         DbgPrint("WARNING: Failed to render glyph!\n");
705                 goto fail;
706       }
707       pitch = glyph->bitmap.pitch;
708     } else {
709       pitch = glyph->bitmap.width;
710     }
711
712     DestRect.left = TextLeft;
713     DestRect.top = TextTop + yoff - glyph->bitmap_top;
714     DestRect.right = TextLeft + glyph->bitmap.width;
715     DestRect.bottom = DestRect.top + glyph->bitmap.rows;
716     bitSize.cx = pitch-1;
717     bitSize.cy = glyph->bitmap.rows-1;
718     MaskRect.right = glyph->bitmap.width;
719     MaskRect.bottom = glyph->bitmap.rows;
720
721     // We should create the bitmap out of the loop at the biggest possible glyph size
722     // Then use memset with 0 to clear it and sourcerect to limit the work of the transbitblt
723
724     HSourceGlyph = EngCreateBitmap(bitSize, pitch, BMF_1BPP, 0, glyph->bitmap.buffer);
725     SourceGlyphSurf = (PSURFOBJ)AccessUserObject(HSourceGlyph);
726
727     // Use the font data as a mask to paint onto the DCs surface using a brush
728     EngBitBlt(SurfObj, NULL, SourceGlyphSurf, NULL, NULL, &DestRect, &SourcePoint, &MaskRect, Brush, &BrushOrigin, 0xAACC);
729
730     EngDeleteSurface(HSourceGlyph);
731
732     TextLeft += glyph->advance.x >> 6;
733     previous = glyph_index;
734
735     String++;
736   }
737   TEXTOBJ_UnlockText( dc->w.hFont );
738   BRUSHOBJ_UnlockBrush(hBrush);
739   W32kDeleteObject( hBrush );
740   DC_ReleasePtr( hDC );
741   return TRUE;
742
743 fail:
744   TEXTOBJ_UnlockText( dc->w.hFont );
745   if( hBrush ){
746     BRUSHOBJ_UnlockBrush(hBrush);
747     W32kDeleteObject( hBrush );
748   }
749   DC_ReleasePtr( hDC );
750   return FALSE;
751 }
752
753 UINT
754 STDCALL
755 W32kTranslateCharsetInfo(PDWORD  Src,
756                                LPCHARSETINFO  CSI,
757                                DWORD  Flags)
758 {
759   UNIMPLEMENTED;
760 }