File:  [WindowsNT SDKs] / q_a / samples / uniput / display.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Thu Aug 9 18:29:48 2018 UTC (7 years, 9 months ago) by root
Branches: msft, MAIN
CVS tags: ntsdk-nov-1993, ntsdk-jul-1993, HEAD
Microsoft Windows NT Build 511 (SDK Final Release) 07-24-1993


/******************************************************************************\
*       This is a part of the Microsoft Source Code Samples. 
*       Copyright (C) 1993 Microsoft Corporation.
*       All rights reserved. 
*       This source code is only intended as a supplement to 
*       Microsoft Development Tools and/or WinHelp documentation.
*       See these sources for detailed information regarding the 
*       Microsoft samples programs.
\******************************************************************************/

/**************************************************************************\
*  display.c -- module to support the main MDI child windows.
*
* This module contains Window Procedure, openDisplay() and closeDisplay()
*  routines.  Call openDisplay() one time per process before creating the
*  first window, and call closeDisplay() one time at process termination.
*
* windows are created in main frame window procedure.
*
* design:  We have one window procedure here for potentially multiple
*  MDI child windows.  The nCharPerLine, SqrHeight, and SqrWidth are
*  stored on a per window basis.  Also, the window class is registered
*  with the style CS_OWNDC.  For this reason, it is possible to select
*  a logical font into the HDC, and it will be there each time you get
*  the DC new for the window.  In this way we have a log font for each
*  window without actually doing any work in this module.
*
*  Some of the data is global, and works for all of the windows.  The
*  startcount & endcount arrays are a good example.  These are computed
*  once when the font is created, but the values remain the same for each
*  window.  Thus we have the following assumption:
*
*   1.  No fonts will be installed or removed while program is running.
*       (CountUCSegments values remain valid for run time duration).
*
*
*  There are WM_USER+ messages to set values for this window, and to
*  notify it of global changes.  Looking at the create time, user message
*  stream is helpful.  On the WM_CREATE message, we send ourselves a
*  WMU_NEWFONT message to create a logical font and count the number of
*  character ranges (segments).  Before returning from this message, we
*  send ourselves a WMU_NEWRANGE message to set the title, and the
*  horizontal scroll bar correctly.
*
*
\**************************************************************************/
#define UNICODE

#include <windows.h>
#include "uniput.h"
#include "display.h"


/* global variables store the start and end codepoints for UC ranges. */
#define MAXSEGMENTS  100
USHORT *endCount= NULL;
USHORT *startCount= NULL;

int CountUCSegments (HDC);
/* error return value from CountUCSegments */
#define SEGMENTERROR -1


/* conversion between (x,y) pairs and rectangle index */
int transXYtoIndex (int, int, int, int, int);
int transIndextoRect (int, PRECT, int, int, int);


/* window extra bytes for use to store window specific data (see register class) */
#define GWLU_NCHAR        0
#define GWLU_SQRHEIGHT    4
#define GWLU_SQRWIDTH     8





/* Global logfont.  Used for CreateFontIndirect().
 *  also regerenced in the uniput.c file.
 */
LOGFONT logfont = {
      UCFONTHEIGHT ,
      UCFONTWIDTH ,
       0 ,
       0 ,
     400 ,
       0 ,
       0 ,
       0 ,
       UNICODE_CHARSET ,
       0 ,
       0 ,
       2 ,
       2 ,
      TEXT("Lucida Sans Unicode")};


/* Global, class specific data.
 *  ought to allocate once per class, and free once at app exit time.
 */
HDC hdcMemXOR;
HBITMAP hbmMemXOR;
PVOID pbitsXOR, pbitsAND;

int FontWidth, FontHeight;
int nSegments;

/**************************************************************************\
*
*  function:  openDisplay()
*
*  Global variables:
*   HDC hdcMemXOR;
*   HBITMAP hbmMemXOR;
*   PVOID pbitsXOR, pbitsAND;
*   int FontWidth, FontHeight;
*   int nSegments;
*
*  returns:  TRUE - if success,  FALSE - if fail.
*
*  essential side effect:
*   Registers window class, and initial global variables.
\**************************************************************************/
int openDisplay(VOID )
{
WNDCLASS  wc;
static int cxCursor, cyCursor;
HFONT hfont;

  /* Register the window class*/
  wc.style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC;
  wc.lpfnWndProc = (WNDPROC)DisplayWndProc;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 12;
  wc.hInstance = hInst;
  wc.hIcon = LoadIcon(hInst, TEXT("uniputIcon"));
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = GetStockObject (WHITE_BRUSH);
  wc.lpszMenuName = NULL;
  wc.lpszClassName = DISPLAYCLASS;

  if (!RegisterClass(&wc)) return (FALSE);

  cxCursor = GetSystemMetrics (SM_CXCURSOR);
  cyCursor = GetSystemMetrics (SM_CYCURSOR);

  /* get pointer to 0-init memory */
  pbitsAND = (PVOID) LocalAlloc (LPTR, cxCursor*cyCursor/8);

  /* Create a memory DC to draw into for creating cursors. */
  hdcMemXOR = CreateCompatibleDC (NULL);
  hbmMemXOR = CreateBitmap (cxCursor,cyCursor,1,4,NULL);
  SelectObject (hdcMemXOR, hbmMemXOR);

  /* set text modes for the memory HDC */
  SetBkMode (hdcMemXOR, TRANSPARENT);
  SetTextAlign (hdcMemXOR, TA_CENTER | TA_TOP);

  /* set a unicode font into the memory DC */
  logfont.lfHeight = cyCursor  *2/3;  // HACK.. scale down Y
  logfont.lfWidth  = cxCursor  *2/3;
  hfont = CreateFontIndirect (&logfont);
  SelectObject (hdcMemXOR, hfont);

  /* get pointer to be used later as pointer to bitmap bits */
  pbitsXOR = (PVOID) LocalAlloc (LPTR, cxCursor*cyCursor/2);

  /* Assume that we got a unicode font.
   *  Count the number of segments, and fill in the proper global
   *  variables specifying the code point ranges covered.
   */
  nSegments = CountUCSegments (hdcMemXOR); /* slow computation */


  /* verify that we have SOME ranges to work with */
  if (nSegments == SEGMENTERROR) return FALSE;

  /* warn the user if we can't find the right font */
  if (nSegments < 30)
    MessageBox (NULL,
        TEXT("Working with limited codepoint coverage. \n Install uclucida.ttf"),
        TEXT("Warning: Lucida Sans Unicode font not found."), MB_OK);



  FontWidth  = UCFONTWIDTH;
  FontHeight = UCFONTHEIGHT;

  return TRUE;
}

/**************************************************************************\
*
*  function:  closeDisplay()
*
*  Global variables:
*   HDC hdcMemXOR;
*   HBITMAP hbmMemXOR;
*   PVOID pbitsXOR, pbitsAND;
*
*  essential side effect:
*   Frees global variables.
\**************************************************************************/
int closeDisplay(VOID)
{
HFONT hfont;

  hfont = SelectObject  (hdcMemXOR, GetStockObject(SYSTEM_FONT));
  DeleteObject (hfont);
  DeleteDC (hdcMemXOR);
  DeleteObject (hbmMemXOR);

  LocalFree (LocalHandle (pbitsXOR));
  LocalFree (LocalHandle (pbitsAND));
  return TRUE;
}


/**************************************************************************\
*
*  function:  DisplayWndProc()
*
*  input parameters:  normal window procedure parameters.
*
\**************************************************************************/
LRESULT CALLBACK DisplayWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HFONT  hfont, hfontOld;

static HDC hdc;
static RECT rect;
static int iSeg;
static TCHAR buffer[100];

/* rDown and index used as the user points to a square. */
static RECT rDown;
static int index;

static WCHAR DragDropChar;
static HICON hIcon;



  switch (message) {

    /**********************************************************************\
    *  WM_CREATE
    *
    * Set up the LOGFONT in the HDC for this window.
    \**********************************************************************/
    case WM_CREATE:
      SendMessage (hwnd, WMU_SETNCHAR, 16, 0);
      SendMessage (hwnd, WMU_NEWFONT, FontWidth, FontHeight);
    break;


    /**********************************************************************\
    *  WM_DESTROY
    *
    * Get rid of the logical font we create for each display window.
    *  relying here on CS_ONWDC
    \**********************************************************************/
    case WM_DESTROY:
      hdc = GetDC (hwnd);
      hfont = SelectObject  (hdc, GetStockObject(SYSTEM_FONT));
      DeleteObject (hfont);
      ReleaseDC (hwnd, hdc);

      if (startCount != NULL) LocalFree (LocalHandle (startCount));
      if (endCount != NULL) LocalFree (LocalHandle (endCount));

    break;





    /**********************************************************************\
    *  WMU_SETNCHAR
    *
    * wParam - nCharPerLine
    *
    \**********************************************************************/
    case WMU_SETNCHAR:
      SetWindowLong (hwnd, GWLU_NCHAR, (int) wParam);
      InvalidateRect (hwnd, NULL, TRUE);
    break;

    /**********************************************************************\
    *  WMU_NEWFONT
    *
    * wParam - Width
    * lParam - Height
    *
    * Create font, select it into the HDC, and reset ranges.
    \**********************************************************************/
    case WMU_NEWFONT: {

      hdc = GetDC(hwnd);

      FontWidth  = (int) wParam;
      FontHeight = (int) lParam;
      logfont.lfHeight = FontHeight;
      logfont.lfWidth  = FontWidth;

      hfont = CreateFontIndirect (&logfont);
      hfontOld = SelectObject (hdc, hfont);
      DeleteObject (hfontOld);

      ReleaseDC (hwnd, hdc);


      SetScrollRange (hwnd, SB_HORZ, 0, (nSegments-1), TRUE);
      SetScrollPos (hwnd, SB_HORZ, 0, TRUE);

      SendMessage (hwnd, WMU_NEWRANGE, 0,0);

    } return TRUE;


    /**********************************************************************\
    *  WMU_NEWRANGE
    *
    *
    * Range changes, or font size changes, or title status changes.
    \**********************************************************************/
    case WMU_NEWRANGE: {
      int sqrHeight, sqrWidth;
      TEXTMETRIC tm;
      int i;

      hdc = GetDC(hwnd);
      GetTextMetrics (hdc, &tm);
      ReleaseDC (hwnd, hdc);

      /* index into the start, end arrays stored in scroll bar */
      iSeg = GetScrollPos (hwnd, SB_HORZ);

      /* Set the window title text to show display range. */
      wsprintf (buffer, TEXT("[%04x, %04x]"),
                                  (int)startCount[iSeg],
                                  (int)endCount[iSeg]);

      /* if we are supposed to look up the character range name,
       *  then step through the ranges stored in the RangeName
       *  table.  Find the correct one, and reset the buffer string.
       */
      if (gShowNames) {
        for (i = 0; i< NRANGE; i++) {
          if ((RangeName[i].start <= startCount[iSeg]) &&
              ( startCount[iSeg] <= RangeName[i].end))

            wsprintf (buffer, TEXT("%s [%04x, %04x]"),
                                  RangeName[i].String,
                                  (int)startCount[iSeg],
                                  (int)endCount[iSeg]);

        }
      }
      SetWindowText (hwnd, buffer);

      sqrHeight =  tm.tmHeight + tm.tmExternalLeading;
      sqrWidth = tm.tmMaxCharWidth;

      SetWindowLong (hwnd, GWLU_SQRHEIGHT,sqrHeight);
      SetWindowLong (hwnd, GWLU_SQRWIDTH, sqrWidth );

    } return TRUE;









    /**********************************************************************\
    *  WM_LBUTTONDOWN
    *
    * Static, shared variables set in WM_LBUTTONDOWN:
    *   rDown, hIcon, DragDropChar
    *
    \**********************************************************************/
    case WM_LBUTTONDOWN: {
      int x,y;
      int nCharPerLine;
      int sqrHeight, sqrWidth;
      nCharPerLine = GetWindowLong (hwnd, GWLU_NCHAR);
      sqrHeight    = GetWindowLong (hwnd, GWLU_SQRHEIGHT);
      sqrWidth     = GetWindowLong (hwnd, GWLU_SQRWIDTH );



      x = (int)LOWORD (lParam);
      y = (int)HIWORD (lParam);

      index = transXYtoIndex (x,y, sqrWidth, sqrHeight, nCharPerLine);

      /* verify that the index is within the shown segment range */
      iSeg= GetScrollPos (hwnd, SB_HORZ);
      if (index > (endCount[iSeg]- startCount[iSeg])) return 0;

      DragDropChar = index + startCount[iSeg];

      transIndextoRect (index, &rDown, sqrWidth, sqrHeight, nCharPerLine);

      hdc = GetDC (hwnd);
      InvertRect (hdc, &rDown);
      ReleaseDC (hwnd, hdc);


      /* Create a cursor which represents the character.
       * Global variables used:
       *   HDC hdcMemXOR;
       *   HBITMAP hbmMemXOR;
       *   PVOID pbitsXOR, pbitsAND;
       */
      {
      int cxCursor, cyCursor;
      RECT rect;

      cxCursor = GetSystemMetrics (SM_CXCURSOR);
      cyCursor = GetSystemMetrics (SM_CYCURSOR);

      rect.left = rect.top = 0;
      rect.right = cxCursor; rect.bottom = cyCursor;


      FrameRect (hdcMemXOR, &rect, GetStockObject (BLACK_BRUSH));
      InflateRect (&rect, -1, -1);
      FillRect (hdcMemXOR, &rect, GetStockObject (LTGRAY_BRUSH));
      FrameRect (hdcMemXOR, &rect, GetStockObject (GRAY_BRUSH));
      InflateRect (&rect, -1, -1);
      SelectObject (hdcMemXOR, GetStockObject (WHITE_PEN));
      MoveToEx (hdcMemXOR, rect.right, rect.top, NULL);
      LineTo (hdcMemXOR,rect.left, rect.top);
      LineTo (hdcMemXOR,rect.left, rect.bottom);

      ExtTextOut(hdcMemXOR, cxCursor/2,0, ETO_CLIPPED, &rect,
                   (LPCWSTR)&DragDropChar, 1, NULL);

      GetBitmapBits (hbmMemXOR, cxCursor*cyCursor/2, pbitsXOR);

      hIcon = CreateIcon( GetModuleHandle(NULL),
              cxCursor,cyCursor, 1,4,
              pbitsAND,
              pbitsXOR);

      SetCursor ((HCURSOR)hIcon);
      }



      GdiFlush ();
      SetCapture (hwnd);
    } break;

    /**********************************************************************\
    *  WM_LBUTTONUP
    *
    * Static, shared variables set in WM_LBUTTONDOWN:
    *   rDown, hIcon, DragDropChar
    *
    \**********************************************************************/
    case WM_LBUTTONUP: {
      POINT p;
      HWND hwndTarget, hwndTitle;
#define NUMCHARS  255
      TCHAR buffer[NUMCHARS];


      if (GetCapture() == hwnd) {

        p.x = (int)(short)LOWORD (lParam);
        p.y = (int)(short)HIWORD (lParam);

        ClientToScreen (hwnd, &p);
        hwndTarget = WindowFromPoint (p);

        if ((GetWindowThreadProcessId (hwnd, NULL)) !=
            (GetWindowThreadProcessId (hwndTarget, NULL))) {

          /* hack.  unipad has a client window which gets the chars,
           *  but we want to display the frame windows text (title bar),
           *  so try to get the parent of the target for Title purposes.
           */
          hwndTitle = (GetParent(hwndTarget)) ? GetParent(hwndTarget) : hwndTarget;
          GetWindowText (hwndTitle, buffer, NUMCHARS);

          SendMessage (hwndTarget, WM_CHAR, (WPARAM) DragDropChar, 0);
          SendMessage (hwndStatus, WMU_CHARACTER,
                         (WPARAM) DragDropChar, (LPARAM)hwndTarget);
          SendMessage (hwndStatus, WMU_SETTARGETNAME,
                         (WPARAM) IsWindowUnicode (hwndTarget), (LPARAM)buffer);
        } /* end different process */

        Beep (40,40);

        hdc = GetDC (hwnd);
        InvertRect (hdc, &rDown);
        ReleaseDC (hwnd, hdc);
        GdiFlush ();
        ReleaseCapture ();
        SetCursor ((HCURSOR)LoadCursor (NULL, IDC_ARROW));
        DestroyIcon (hIcon);
      }
    } break;



    /**********************************************************************\
    *  WM_HSCROLL
    *
    * Step through the character ranges.
    * In every case, inform the window the range has changed,
    *  and invalidate it to force a repaint.
    \**********************************************************************/
    case WM_HSCROLL:

      switch (LOWORD(wParam)){
        int OldPos, NewPos;

        case SB_PAGEDOWN:
        case SB_LINEDOWN:
          OldPos = GetScrollPos (hwnd, SB_HORZ);
          SetScrollPos (hwnd, SB_HORZ, (OldPos+1), TRUE);
          SendMessage (hwnd,WMU_NEWRANGE, 0,0);
          InvalidateRect (hwnd, NULL, TRUE);
        break;

        case SB_PAGEUP:
        case SB_LINEUP:
          OldPos = GetScrollPos (hwnd, SB_HORZ);
          SetScrollPos (hwnd, SB_HORZ, (OldPos-1), TRUE);
          SendMessage (hwnd,WMU_NEWRANGE, 0,0);
          InvalidateRect (hwnd, NULL, TRUE);
        break;

        case SB_THUMBPOSITION:
          OldPos = GetScrollPos (hwnd, SB_HORZ);
          NewPos = HIWORD (wParam);
          SetScrollPos (hwnd, SB_HORZ, NewPos, TRUE);
          SendMessage (hwnd,WMU_NEWRANGE, 0,0);
          InvalidateRect (hwnd, NULL, TRUE);
        break;

      }

    break;







    /**********************************************************************\
    *  WM_SIZE
    *
    \**********************************************************************/
    case WM_SIZE:
      /* make sure that scroll metrics are ok */
      SendMessage (hwnd, WMU_NEWRANGE, 0,0);

    break;  /* fall through to MDIChildProc */


    /**********************************************************************\
    *  WM_PAINT
    *
    \**********************************************************************/
    case WM_PAINT: {
      HDC hdc;
      PAINTSTRUCT ps;
      RECT rect;
      POINT  point;
      int i;
      USHORT start, end;
      WCHAR outChar;
      USHORT codepoint;
      int nCharPerLine;
      int sqrHeight, sqrWidth;
      nCharPerLine = GetWindowLong (hwnd, GWLU_NCHAR);
      sqrHeight    = GetWindowLong (hwnd, GWLU_SQRHEIGHT);
      sqrWidth     = GetWindowLong (hwnd, GWLU_SQRWIDTH );


      hdc = BeginPaint(hwnd, &ps);
      SetBkMode (hdc, TRANSPARENT);

      iSeg= GetScrollPos (hwnd, SB_HORZ);
      start = startCount[iSeg];
      end = endCount[iSeg];

      /* ensure that we are in a valid range... some fonts have problems */
      if (start != 0xffff)

        for (codepoint = start, i=0; codepoint<=end; codepoint++,i++) {

          /* paint box and frame it */
          transIndextoRect (i, &rect, sqrWidth, sqrHeight, nCharPerLine);
          InflateRect (&rect, -1, -1);
          FillRect (hdc, &rect, GetStockObject (LTGRAY_BRUSH));
          InflateRect (&rect, 1, 1);
          FrameRect (hdc, &rect, GetStockObject (GRAY_BRUSH));
          InflateRect (&rect, -1, -1);
          SelectObject (hdc, GetStockObject (WHITE_PEN));
          MoveToEx (hdc, rect.right, rect.top, NULL);
          LineTo (hdc,rect.left, rect.top);
          LineTo (hdc,rect.left, rect.bottom);



          /* set point that we will draw glyph at */
          point.x = (rect.right + rect.left)/2;
          point.y = rect.top;
          SetTextAlign (hdc, TA_CENTER | TA_TOP);
          SetTextColor (hdc, PALETTEINDEX (0));


          /* special case the non-spacing diacritic marks. U+0300 -> U+036F
           *  Write a space first, for them to 'modify.'
           */
          if ( (0x0300 <= codepoint) && (codepoint <= 0x036F) ) {
            outChar = (WCHAR) 0x0020;
            TextOutW (hdc, 0,0, &outChar, 1);
          }

          outChar = (WCHAR) codepoint;
          ExtTextOut(hdc, point.x, point.y, ETO_CLIPPED, &rect, (LPCWSTR)&outChar, 1, NULL);



          /* fill in unicode code point in hex */
          if (gShowhex) {
            int nchar;
            HANDLE hfonttemp;

            nchar = wsprintf (buffer, TEXT("%04x"), (int) codepoint);
            hfonttemp = SelectObject (hdc,GetStockObject (SYSTEM_FIXED_FONT));

            point.y = rect.bottom;
            SetTextAlign (hdc, TA_CENTER | TA_BOTTOM);
            SetTextColor (hdc, PALETTEINDEX (5));

            TextOut( hdc, point.x, point.y,
                          buffer, nchar);
            SelectObject (hdc,hfonttemp);
          }


        } /* end for */

      EndPaint (hwnd, &ps);
    } return FALSE; /* end WM_PAINT */




  } /* end switch */

  return (DefMDIChildProc(hwnd, message, wParam, lParam));
}




/**************************************************************************\
*
* Need a mapping between the (x,y) pair, and the index of the square on
*  the window.  Two routines provide this... one for each direction.
*
\**************************************************************************/

/**********************************************************************\
*  transXYtoIndex
*
*  Given x & y values, return the index.
*
\**********************************************************************/
int transXYtoIndex (int x, int y,
     int sqrWidth, int sqrHeight, int nCharPerLine)
{
    x /= sqrWidth;
    if (x < 0) x = 0;
    if (x >= nCharPerLine) x = nCharPerLine-1;

    y /= sqrHeight;
    if (y < 0) y = 0;

    return ( (y * nCharPerLine) + x);
}


/**********************************************************************\
*  transIndextoRect
*
*  Given an index, i.e. the number of one of the squares on the display
*   window, fill in the rectangle structure.
*
\**********************************************************************/
int transIndextoRect (int index, PRECT pr,
     int sqrWidth, int sqrHeight, int nCharPerLine)
{
int x,y;

    x = index % nCharPerLine;
    y = index / nCharPerLine;

    pr->left = x*sqrWidth;
    pr->top = y*sqrHeight;
    pr->right = pr->left +sqrWidth;
    pr->bottom = pr->top +sqrHeight;

    return TRUE;
}






/**************************************************************************\
*
* All of the code below is used for parsing 'font data.'  It will only
*  make sense if you have a copy of the True Type font spec.  In short,
*  we grab the 'cmap' table, look through it for a subtable, and then
*  get two parallel arrays from the subtable.  Complications arise because
*  the true type data is 'BIG ENDIAN' and NT is being run 'little endian.'
*  For this reason, once we locate the short or long, we call Swap* to
*  change the byte ordering.
*
\**************************************************************************/


VOID SwapShort (PUSHORT);
VOID SwapULong  (PULONG);



typedef struct tagTABLE{
    USHORT platformID;
    USHORT encodingID;
    ULONG  offset;
} TABLE, *PTABLE;

typedef struct tagSUBTABLE{
    USHORT format;
    USHORT length;
    USHORT version;
    USHORT segCountX2;
    USHORT searchRange;
    USHORT entrySelector;
    USHORT rangeShift;
} SUBTABLE, *PSUBTABLE;


/* 'cmap' is passed in by value in a DWORD */
#define CMAPHEX  0x70616d63
#define NBYTES   256
#define OFFSETERROR  0



/**************************************************************************\
*
*  function:  CountUCSegments()
*
*  input parameters:
*   hdc - with the logical font set into it.
*   prect - pointer to client rectangle.
*
*  Global variables:
*   startCount
*   endCount
*
*  returns:
*   number of UC segments or
*   SEGMENTERROR if there is some kind of error.
*
*  essential side effect:
*   Fills in global startCount, endCount arrays.
\**************************************************************************/
int CountUCSegments (HDC hdc)
{
DWORD       cbData;
USHORT      aShort[2];
DWORD       nBytes;
USHORT      i, nTables;
PTABLE      pTable;
PSUBTABLE   pSubTable;
ULONG       offset,offsetFormat4;
USHORT      segCount;
BYTE        buffer[NBYTES];




    /* find number of "subtables", second long in cmap */
    nBytes=GetFontData (hdc, CMAPHEX, 0, aShort, 4);
    if (nBytes == GDI_ERROR) {
      MessageBox (NULL, MBGETFONTDATAERR,MBERROR , MBERRORFLAGS);
      return SEGMENTERROR;
    }
    if (nBytes == 0) {
      MessageBox (NULL, TEXT("No 'cmap' table."),MBERROR , MBERRORFLAGS);
      return SEGMENTERROR;
    }
    nTables = aShort[1];
    SwapShort (&nTables);


    cbData = nTables * sizeof(TABLE);
    if (cbData >NBYTES) {
      MessageBox (NULL, TEXT("cbData >NBYTES"),MBERROR , MBERRORFLAGS);
      return SEGMENTERROR;
    }

    /* get array of subtables information.  Check each one for 3,1*/
    nBytes=GetFontData (hdc, CMAPHEX, 4, buffer, cbData);
    pTable = (PTABLE)buffer;
    offsetFormat4 = OFFSETERROR;
    for (i = 0; i< nTables; i++) {

        SwapShort (&(pTable->encodingID));
        SwapShort (&(pTable->platformID));

        if ((pTable->platformID == 3)&&(pTable->encodingID == 1)) {
          offsetFormat4 = pTable->offset;
          SwapULong (&offsetFormat4);
          break;
        }
        pTable++;
    }

    /* verify that we got the correct offset to the FORMAT 4 subtable */
    if (offsetFormat4 == OFFSETERROR){
      MessageBox (NULL, TEXT("Can not find 3,1 subtable"),MBERROR , MBERRORFLAGS);
      return SEGMENTERROR;
    }

    /* Get the beginning of the subtable, especially the segment count */
    nBytes=GetFontData (hdc, CMAPHEX, offsetFormat4, buffer, sizeof(SUBTABLE));
    pSubTable = (PSUBTABLE) buffer;
    SwapShort (&(pSubTable->format));
    SwapShort (&(pSubTable->segCountX2));

    if (pSubTable->format != 4){
      MessageBox (NULL, TEXT("format !=4"), MBERROR, MBERRORFLAGS);
      return SEGMENTERROR;
    }

    segCount = pSubTable->segCountX2 / 2;

    /* Now that we know how many segments that the font contains,
     *  free up the old memory, and realloc. the two global arrays.
     */
    if (startCount != NULL) LocalFree (LocalHandle (startCount));
    if (endCount != NULL) LocalFree (LocalHandle (endCount));
    startCount = LocalAlloc (LPTR, segCount * sizeof(USHORT));
    endCount = LocalAlloc (LPTR, segCount * sizeof(USHORT));

    if ((startCount == NULL) || (endCount == NULL)) {
      MessageBox (NULL, TEXT("LocalAlloc failed"), MBERROR, MBERRORFLAGS);
      return SEGMENTERROR;
    }

    /* read in the array of endCount values */
    offset = offsetFormat4
           + (7 * sizeof (USHORT));  /* skip constant # bytes in subtable */
    cbData = segCount * sizeof (USHORT);
    nBytes=GetFontData (hdc, CMAPHEX, offset, endCount, cbData );
    for (i = 0; i<segCount; i++)
        SwapShort (& (endCount[i]));

    /* read in the array of startCount values */
    offset = offsetFormat4
           + (7 * sizeof (USHORT))   /* skip constant # bytes in subtable */
           + (segCount * sizeof (USHORT)) /* skip endCount array */
           + sizeof (USHORT);             /* skip reservedPad */
    cbData = segCount * sizeof (USHORT);
    nBytes=GetFontData (hdc, CMAPHEX, offset, startCount, cbData );
    for (i = 0; i<segCount; i++)
        SwapShort (& (startCount[i]));


    return segCount;
}










VOID SwapShort (PUSHORT p)
{
SHORT temp;

    temp =(SHORT)( HIBYTE (*p) + (LOBYTE(*p) << 8));
    *p = temp;
}



VOID SwapULong (PULONG p)
{
ULONG temp;

    temp = (LONG) ((BYTE) *p);
    temp <<= 8;
    *p >>=8;

    temp += (LONG) ((BYTE) *p);
    temp <<= 8;
    *p >>=8;

    temp += (LONG) ((BYTE) *p);
    temp <<= 8;
    *p >>=8;

    temp += (LONG) ((BYTE) *p);
    *p = temp;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.