branch update for HEAD-2003050101
[reactos.git] / subsys / win32k / objects / text.c
index ded81fd..b5e7026 100644 (file)
@@ -3,14 +3,19 @@
 #undef WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include <ddk/ntddk.h>
+#include <internal/safe.h>
+#include <win32k/brush.h>
 #include <win32k/dc.h>
 #include <win32k/text.h>
 #include <win32k/kapi.h>
-#include <freetype/freetype.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
 
 #include "../eng/handle.h"
 
-// #define NDEBUG
+#include <include/inteng.h>
+
+#define NDEBUG
 #include <win32k/debug1.h>
 
 FT_Library  library;
@@ -33,14 +38,57 @@ BOOL InitFontSupport()
     return FALSE;
   }
 
+#ifndef TODO
+  W32kAddFontResource(L"\\SystemRoot\\media\\fonts\\arial.ttf");
+#endif
   W32kAddFontResource(L"\\SystemRoot\\media\\fonts\\helb____.ttf");
   W32kAddFontResource(L"\\SystemRoot\\media\\fonts\\timr____.ttf");
 
-  DbgPrint("All fonts loaded\n");
+  DPRINT("All fonts loaded\n");
 
   return TRUE;
 }
 
+static NTSTATUS
+GetFontObjectsFromTextObj(PTEXTOBJ TextObj, HFONT *FontHandle, PFONTOBJ *FontObj, PFONTGDI *FontGDI)
+{
+  UINT i;
+  NTSTATUS Status = STATUS_SUCCESS;
+
+  ASSERT(NULL != TextObj && NULL != TextObj->GDIFontHandle);
+  if (NULL != TextObj && NULL != TextObj->GDIFontHandle)
+  {
+    if (NT_SUCCESS(Status) && NULL != FontHandle)
+    {
+      *FontHandle = TextObj->GDIFontHandle;
+    }
+    if (NT_SUCCESS(Status) && NULL != FontObj)
+    {
+      *FontObj = AccessUserObject((ULONG) TextObj->GDIFontHandle);
+      if (NULL == *FontObj)
+      {
+       ASSERT(FALSE);
+       Status = STATUS_INVALID_HANDLE;
+      }
+    }
+    if (NT_SUCCESS(Status) && NULL != FontGDI)
+    {
+      *FontGDI = AccessInternalObject((ULONG) TextObj->GDIFontHandle);
+      if (NULL == *FontGDI)
+      {
+       ASSERT(FALSE);
+       Status = STATUS_INVALID_HANDLE;
+      }
+    }
+  }
+  else
+  {
+    Status = STATUS_INVALID_HANDLE;
+  }
+
+  return Status;
+}
+
 int
 STDCALL
 W32kAddFontResource(LPCWSTR  Filename)
@@ -62,8 +110,8 @@ W32kAddFontResource(LPCWSTR  Filename)
   IO_STATUS_BLOCK Iosb;
 
   NewFont = (HFONT)CreateGDIHandle(sizeof( FONTGDI ), sizeof( FONTOBJ ));
-  FontObj = (PFONTOBJ) AccessUserObject( NewFont );
-  FontGDI = (PFONTGDI) AccessInternalObject( NewFont );
+  FontObj = (PFONTOBJ) AccessUserObject( (ULONG) NewFont );
+  FontGDI = (PFONTGDI) AccessInternalObject( (ULONG) NewFont );
 
   RtlCreateUnicodeString(&uFileName, (LPWSTR)Filename);
 
@@ -74,7 +122,7 @@ W32kAddFontResource(LPCWSTR  Filename)
 
   if (!NT_SUCCESS(Status))
   {
-    DbgPrint("Could not open module file: %S\n", Filename);
+    DPRINT1("Could not open module file: %S\n", Filename);
     return 0;
   }
 
@@ -82,7 +130,7 @@ W32kAddFontResource(LPCWSTR  Filename)
   Status = NtQueryInformationFile(FileHandle, &Iosb, &FileStdInfo, sizeof(FileStdInfo), FileStandardInformation);
   if (!NT_SUCCESS(Status))
   {
-    DbgPrint("Could not get file size\n");
+    DPRINT1("Could not get file size\n");
     return 0;
   }
 
@@ -92,7 +140,7 @@ W32kAddFontResource(LPCWSTR  Filename)
 
   if (buffer == NULL)
   {
-    DbgPrint("could not allocate memory for module");
+    DPRINT1("could not allocate memory for module");
     return 0;
   }
 
@@ -100,7 +148,7 @@ W32kAddFontResource(LPCWSTR  Filename)
   Status = NtReadFile(FileHandle, 0, 0, 0, &Iosb, buffer, FileStdInfo.EndOfFile.u.LowPart, 0, 0);
   if (!NT_SUCCESS(Status))
   {
-    DbgPrint("could not read module file into memory");
+    DPRINT1("could not read module file into memory");
     ExFreePool(buffer);
     return 0;
   }
@@ -110,12 +158,12 @@ W32kAddFontResource(LPCWSTR  Filename)
   error = FT_New_Memory_Face(library, buffer, size, 0, &face);
   if (error == FT_Err_Unknown_File_Format)
   {
-    DbgPrint("Unknown font file format\n");
+    DPRINT1("Unknown font file format\n");
     return 0;
   }
   else if (error)
   {
-    DbgPrint("Error reading font file (error code: %u)\n", error); // 48
+    DPRINT1("Error reading font file (error code: %u)\n", error); // 48
     return 0;
   }
 
@@ -127,9 +175,8 @@ W32kAddFontResource(LPCWSTR  Filename)
   FontGDI->TextMetric.tmDescent = face->size->metrics.descender; // units below baseline
   FontGDI->TextMetric.tmHeight = FontGDI->TextMetric.tmAscent + FontGDI->TextMetric.tmDescent;
 
-  DbgPrint("Family name: %s\n", face->family_name);
-  DbgPrint("Style name: %s\n", face->style_name);
-  DbgPrint("Num glyphs: %u\n", face->num_glyphs);
+  DPRINT("Font loaded: %s (%s)\n", face->family_name, face->style_name);
+  DPRINT("Num glyphs: %u\n", face->num_glyphs);
 
   // Add this font resource to the font table
   FontTable[FontsLoaded].hFont = NewFont;
@@ -145,24 +192,60 @@ W32kAddFontResource(LPCWSTR  Filename)
   return 1;
 }
 
+NTSTATUS
+TextIntCreateFontIndirect(CONST LPLOGFONTW lf, HFONT *NewFont)
+{
+  PTEXTOBJ TextObj;
+  NTSTATUS Status = STATUS_SUCCESS;
+
+  *NewFont = TEXTOBJ_AllocText();
+  if (NULL != *NewFont)
+  {
+    TextObj = TEXTOBJ_LockText(*NewFont);
+    if (NULL != TextObj)
+    {
+      memcpy(&TextObj->logfont, lf, sizeof(LOGFONTW));
+      if (lf->lfEscapement != lf->lfOrientation)
+      {
+       /* this should really depend on whether GM_ADVANCED is set */
+       TextObj->logfont.lfOrientation = TextObj->logfont.lfEscapement;
+      }
+      TEXTOBJ_UnlockText(*NewFont);
+    }
+    else
+    {
+      ASSERT(FALSE);
+      Status = STATUS_INVALID_HANDLE;
+    }
+  }
+  else
+  {
+    Status = STATUS_NO_MEMORY;
+  }
+
+  return Status;
+}
+
 HFONT
 STDCALL
 W32kCreateFont(int  Height,
-                      int  Width,
-                      int  Escapement,
-                      int  Orientation,
-                      int  Weight,
-                      DWORD  Italic,
-                      DWORD  Underline,
-                      DWORD  StrikeOut,
-                      DWORD  CharSet,
-                      DWORD  OutputPrecision,
-                      DWORD  ClipPrecision,
-                      DWORD  Quality,
-                      DWORD  PitchAndFamily,
-                      LPCWSTR  Face)
-{
-  LOGFONT logfont;
+               int  Width,
+               int  Escapement,
+               int  Orientation,
+               int  Weight,
+               DWORD  Italic,
+               DWORD  Underline,
+               DWORD  StrikeOut,
+               DWORD  CharSet,
+               DWORD  OutputPrecision,
+               DWORD  ClipPrecision,
+               DWORD  Quality,
+               DWORD  PitchAndFamily,
+               LPCWSTR  Face)
+{
+  LOGFONTW logfont;
+  HFONT NewFont;
+  NTSTATUS Status = STATUS_SUCCESS;
 
   logfont.lfHeight = Height;
   logfont.lfWidth = Width;
@@ -178,40 +261,45 @@ W32kCreateFont(int  Height,
   logfont.lfQuality = Quality;
   logfont.lfPitchAndFamily = PitchAndFamily;
 
-  if(Face)
-    memcpy(logfont.lfFaceName, Face, sizeof(logfont.lfFaceName));
+  if (NULL != Face)
+  {
+    Status = MmCopyFromCaller(logfont.lfFaceName, Face, sizeof(logfont.lfFaceName));
+  }
   else
-    logfont.lfFaceName[0] = '\0';
+  {
+    logfont.lfFaceName[0] = L'\0';
+  }
+
+  if (NT_SUCCESS(Status))
+    {
+    Status = TextIntCreateFontIndirect(&logfont, &NewFont);
+    }
 
-  return W32kCreateFontIndirect(&logfont);
+  return NT_SUCCESS(Status) ? NewFont : NULL;
 }
 
 HFONT
 STDCALL
-W32kCreateFontIndirect(CONST LPLOGFONT  lf)
+W32kCreateFontIndirect(CONST LPLOGFONTW lf)
 {
-  HFONT hFont = 0;
-  PTEXTOBJ fontPtr;
+  LOGFONTW SafeLogfont;
+  HFONT NewFont;
+  NTSTATUS Status = STATUS_SUCCESS;
 
-  if (lf)
+  if (NULL != lf)
   {
-    if(hFont = TEXTOBJ_AllocText())
+    Status = MmCopyFromCaller(&SafeLogfont, lf, sizeof(LOGFONTW));
+    if (NT_SUCCESS(Status))
     {
-         fontPtr = TEXTOBJ_LockText( hFont );
-         ASSERT( fontPtr );  //I want to know when this happens
-         if( fontPtr ){
-       memcpy(&fontPtr->logfont, lf, sizeof(LOGFONT));
-
-       if (lf->lfEscapement != lf->lfOrientation) {
-         /* this should really depend on whether GM_ADVANCED is set */
-         fontPtr->logfont.lfOrientation = fontPtr->logfont.lfEscapement;
-       }
-               TEXTOBJ_UnlockText( hFont );
-         }
+      Status = TextIntCreateFontIndirect(&SafeLogfont, &NewFont);
     }
   }
+  else
+  {
+    Status = STATUS_INVALID_PARAMETER;
+  }
 
-  return hFont;
+  return NT_SUCCESS(Status) ? NewFont : NULL;
 }
 
 BOOL
@@ -228,7 +316,7 @@ int
 STDCALL
 W32kEnumFontFamilies(HDC  hDC,
                           LPCWSTR  Family,
-                          FONTENUMPROC  EnumFontFamProc,
+                          FONTENUMPROCW  EnumFontFamProc,
                           LPARAM  lParam)
 {
   UNIMPLEMENTED;
@@ -237,8 +325,8 @@ W32kEnumFontFamilies(HDC  hDC,
 int
 STDCALL
 W32kEnumFontFamiliesEx(HDC  hDC,
-                            LPLOGFONT  Logfont,
-                            FONTENUMPROC  EnumFontFamExProc,
+                            LPLOGFONTW  Logfont,
+                            FONTENUMPROCW  EnumFontFamExProc,
                             LPARAM  lParam,
                             DWORD  Flags)
 {
@@ -249,7 +337,7 @@ int
 STDCALL
 W32kEnumFonts(HDC  hDC,
                    LPCWSTR FaceName,
-                   FONTENUMPROC  FontFunc,
+                   FONTENUMPROCW  FontFunc,
                    LPARAM  lParam)
 {
   UNIMPLEMENTED;
@@ -374,7 +462,7 @@ UINT
 STDCALL
 W32kGetOutlineTextMetrics(HDC  hDC,
                                 UINT  Data,
-                                LPOUTLINETEXTMETRIC  otm)
+                                LPOUTLINETEXTMETRICW  otm)
 {
   UNIMPLEMENTED;
 }
@@ -423,26 +511,26 @@ W32kGetTextExtentPoint(HDC  hDC,
                              int  Count,
                              LPSIZE  Size)
 {
-  PDC dc = (PDC)AccessUserObject(hDC);
+  PDC dc = (PDC)AccessUserObject((ULONG) hDC);
   PFONTGDI FontGDI;
   FT_Face face;
   FT_GlyphSlot glyph;
   INT error, pitch, glyph_index, i;
   ULONG TotalWidth = 0, MaxHeight = 0, CurrentChar = 0, SpaceBetweenChars = 5;
 
-  FontGDI = (PFONTGDI)AccessInternalObject(dc->w.hFont);
+  FontGDI = (PFONTGDI)AccessInternalObject((ULONG) dc->w.hFont);
 
   for(i=0; i<Count; i++)
   {
     glyph_index = FT_Get_Char_Index(face, *String);
     error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
-    if(error) DbgPrint("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
+    if(error) DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
     glyph = face->glyph;
 
     if (glyph->format == ft_glyph_format_outline)
     {
       error = FT_Render_Glyph(glyph, ft_render_mode_mono);
-      if(error) DbgPrint("WARNING: Failed to render glyph!\n");
+      if(error) DPRINT1("WARNING: Failed to render glyph!\n");
       pitch = glyph->bitmap.pitch;
     } else {
       pitch = glyph->bitmap.width;
@@ -482,16 +570,59 @@ W32kGetTextFace(HDC  hDC,
 
 BOOL
 STDCALL
-W32kGetTextMetrics(HDC  hDC,
-                         LPTEXTMETRIC  tm)
+W32kGetTextMetrics(HDC hDC,
+                   LPTEXTMETRICW tm)
 {
-  PDC dc = (PDC)AccessUserObject(hDC);
+  PDC dc;
+  PTEXTOBJ TextObj;
   PFONTGDI FontGDI;
+  NTSTATUS Status = STATUS_SUCCESS;
+  TEXTMETRICW SafeTm;
+  FT_Face Face;
+  ULONG Error;
 
-  FontGDI = (PFONTGDI)AccessInternalObject(dc->w.hFont);
-  memcpy(tm, &FontGDI->TextMetric, sizeof(TEXTMETRIC));
+  dc = DC_HandleToPtr(hDC);
+  if (NULL == dc || NULL == tm)
+  {
+    Status = STATUS_INVALID_PARAMETER;
+  }
+  else
+  {
+    TextObj = TEXTOBJ_LockText(dc->w.hFont);
+    if (NULL != TextObj)
+    {
+      Status = GetFontObjectsFromTextObj(TextObj, NULL, NULL, &FontGDI);
+      if (NT_SUCCESS(Status))
+      {
+       Face = FontGDI->face;
+       Error = FT_Set_Pixel_Sizes(Face, TextObj->logfont.lfHeight,
+                                  TextObj->logfont.lfWidth);
+       if (0 != Error)
+         {
+         DPRINT1("Error in setting pixel sizes: %u\n", Error);
+         Status = STATUS_UNSUCCESSFUL;
+         }
+        else
+         {
+         memcpy(&SafeTm, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
+         SafeTm.tmAscent = (Face->size->metrics.ascender + 32) / 64; // units above baseline
+         SafeTm.tmDescent = (Face->size->metrics.descender + 32) / 64; // units below baseline
+         SafeTm.tmHeight = (Face->size->metrics.ascender +
+                            Face->size->metrics.descender + 32) / 64;
+         Status = MmCopyToCaller(tm, &SafeTm, sizeof(TEXTMETRICW));
+         }
+      }
+      TEXTOBJ_UnlockText(dc->w.hFont);
+    }
+    else
+    {
+      ASSERT(FALSE);
+      Status = STATUS_INVALID_HANDLE;
+    }
+    DC_ReleasePtr(hDC);
+  }
 
-  return TRUE;
+  return NT_SUCCESS(Status);
 }
 
 BOOL
@@ -576,11 +707,11 @@ W32kTextOut(HDC  hDC,
   // Fixme: Call EngTextOut, which does the real work (calling DrvTextOut where appropriate)
 
   DC *dc = DC_HandleToPtr(hDC);
-  SURFOBJ *SurfObj = (SURFOBJ*)AccessUserObject(dc->Surface);
-  int error, glyph_index, n, load_flags = FT_LOAD_RENDER, i, j, sx, sy, scc;
+  SURFOBJ *SurfObj = (SURFOBJ*)AccessUserObject((ULONG) dc->Surface);
+  int error, glyph_index, n, i;
   FT_Face face;
   FT_GlyphSlot glyph;
-  ULONG TextLeft, TextTop, SpaceBetweenChars = 2, pitch, previous;
+  ULONG TextLeft, TextTop, pitch, previous;
   FT_Bool use_kerning;
   RECTL DestRect, MaskRect;
   POINTL SourcePoint, BrushOrigin;
@@ -591,7 +722,6 @@ W32kTextOut(HDC  hDC,
   SIZEL bitSize;
   FT_CharMap found = 0, charmap;
   INT yoff;
-  HFONT hFont = 0;
   PFONTOBJ FontObj;
   PFONTGDI FontGDI;
   PTEXTOBJ TextObj;
@@ -608,51 +738,41 @@ W32kTextOut(HDC  hDC,
 
   TextObj = TEXTOBJ_LockText(dc->w.hFont);
 
-  for(i=0; i<FontsLoaded; i++)
-  {
-    if(wcscmp(FontTable[i].FaceName, (LPSTR)TextObj->logfont.lfFaceName) == 0)
-     hFont = FontTable[i].hFont;
-  }
-
-  if(hFont == 0)
+  if (! NT_SUCCESS(GetFontObjectsFromTextObj(TextObj, NULL, &FontObj, &FontGDI)))
   {
-    DbgPrint("Specified font %s is not loaded\n", TextObj->logfont.lfFaceName);
-       goto fail;
+    goto fail;
   }
-
-  FontObj = (PFONTOBJ)AccessUserObject(hFont);
-  FontGDI = (PFONTGDI)AccessInternalObject(hFont);
   face = FontGDI->face;
 
   if (face->charmap == NULL)
   {
-    DbgPrint("WARNING: No charmap selected!\n");
-    DbgPrint("This font face has %d charmaps\n", face->num_charmaps);
+    DPRINT("WARNING: No charmap selected!\n");
+    DPRINT("This font face has %d charmaps\n", face->num_charmaps);
 
     for (n = 0; n < face->num_charmaps; n++)
     {
       charmap = face->charmaps[n];
-      DbgPrint("found charmap encoding: %u\n", charmap->encoding);
+      DPRINT("found charmap encoding: %u\n", charmap->encoding);
       if (charmap->encoding != 0)
       {
         found = charmap;
         break;
       }
     }
-    if (!found) DbgPrint("WARNING: Could not find desired charmap!\n");
+    if (!found) DPRINT1("WARNING: Could not find desired charmap!\n");
     error = FT_Set_Charmap(face, found);
-    if (error) DbgPrint("WARNING: Could not set the charmap!\n");
+    if (error) DPRINT1("WARNING: Could not set the charmap!\n");
   }
 
   error = FT_Set_Pixel_Sizes(face, TextObj->logfont.lfHeight, TextObj->logfont.lfWidth);
   if(error) {
-    DbgPrint("Error in setting pixel sizes: %u\n", error);
+    DPRINT1("Error in setting pixel sizes: %u\n", error);
        goto fail;
   }
 
   // Create the brush
-  PalDestGDI = (PPALGDI)AccessInternalObject(dc->w.hPalette);
-  XlateObj = (PXLATEOBJ)EngCreateXlate(PalDestGDI->Mode, PAL_RGB, dc->w.hPalette, NULL);
+  PalDestGDI = (PPALGDI)AccessInternalObject((ULONG) dc->w.hPalette);
+  XlateObj = (PXLATEOBJ)IntEngCreateXlate(PalDestGDI->Mode, PAL_RGB, dc->w.hPalette, NULL);
   hBrush = W32kCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor));
   Brush = BRUSHOBJ_LockBrush(hBrush);
   EngDeleteXlate(XlateObj);
@@ -684,7 +804,7 @@ W32kTextOut(HDC  hDC,
     glyph_index = FT_Get_Char_Index(face, *String);
     error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
     if(error) {
-      DbgPrint("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
+      DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
       goto fail;
     }
     glyph = face->glyph;
@@ -701,7 +821,7 @@ W32kTextOut(HDC  hDC,
     {
       error = FT_Render_Glyph(glyph, ft_render_mode_mono);
       if(error) {
-        DbgPrint("WARNING: Failed to render glyph!\n");
+        DPRINT1("WARNING: Failed to render glyph!\n");
                goto fail;
       }
       pitch = glyph->bitmap.pitch;
@@ -713,8 +833,8 @@ W32kTextOut(HDC  hDC,
     DestRect.top = TextTop + yoff - glyph->bitmap_top;
     DestRect.right = TextLeft + glyph->bitmap.width;
     DestRect.bottom = DestRect.top + glyph->bitmap.rows;
-    bitSize.cx = pitch-1;
-    bitSize.cy = glyph->bitmap.rows-1;
+    bitSize.cx = pitch;
+    bitSize.cy = glyph->bitmap.rows;
     MaskRect.right = glyph->bitmap.width;
     MaskRect.bottom = glyph->bitmap.rows;
 
@@ -722,10 +842,10 @@ W32kTextOut(HDC  hDC,
     // Then use memset with 0 to clear it and sourcerect to limit the work of the transbitblt
 
     HSourceGlyph = EngCreateBitmap(bitSize, pitch, BMF_1BPP, 0, glyph->bitmap.buffer);
-    SourceGlyphSurf = (PSURFOBJ)AccessUserObject(HSourceGlyph);
+    SourceGlyphSurf = (PSURFOBJ)AccessUserObject((ULONG) HSourceGlyph);
 
     // Use the font data as a mask to paint onto the DCs surface using a brush
-    EngBitBlt(SurfObj, NULL, SourceGlyphSurf, NULL, NULL, &DestRect, &SourcePoint, &MaskRect, Brush, &BrushOrigin, 0xAACC);
+    IntEngBitBlt(SurfObj, NULL, SourceGlyphSurf, NULL, NULL, &DestRect, &SourcePoint, &MaskRect, Brush, &BrushOrigin, 0xAACC);
 
     EngDeleteSurface(HSourceGlyph);
 
@@ -758,3 +878,50 @@ W32kTranslateCharsetInfo(PDWORD  Src,
 {
   UNIMPLEMENTED;
 }
+
+NTSTATUS
+TextIntRealizeFont(HFONT FontHandle)
+{
+  UINT i;
+  NTSTATUS Status = STATUS_SUCCESS;
+  PTEXTOBJ TextObj;
+
+  TextObj = TEXTOBJ_LockText(FontHandle);
+  ASSERT(TextObj);
+  if (NULL != TextObj)
+    {
+    for(i = 0; NULL == TextObj->GDIFontHandle && i < FontsLoaded; i++)
+    {
+      if (0 == wcscmp(FontTable[i].FaceName, TextObj->logfont.lfFaceName))
+      {
+       TextObj->GDIFontHandle = FontTable[i].hFont;
+      }
+    }
+
+    if (NULL == TextObj->GDIFontHandle)
+    {
+      if (0 != FontsLoaded)
+      {
+       DPRINT("Requested font %S not found, using first available font\n",
+              TextObj->logfont.lfFaceName)
+       TextObj->GDIFontHandle = FontTable[0].hFont;
+      }
+      else
+      {
+       DPRINT1("Requested font %S not found, no fonts loaded at all\n",
+               TextObj->logfont.lfFaceName)
+       Status = STATUS_NOT_FOUND;
+      }
+    }
+
+    ASSERT(! NT_SUCCESS(Status) || NULL != TextObj->GDIFontHandle);
+
+    TEXTOBJ_UnlockText(FontHandle);
+  }
+  else
+  {
+    Status = STATUS_INVALID_HANDLE;
+  }
+
+  return Status;
+}