UCONVERT.C
/**************************************************************************\ 
* uconvert.c -- convert to/from unicode using 
*                MulitByteToWideChar & WideCharToMulitByte 
* 
*         Steve Firebaugh 
*         Microsoft Developer Support 
*         Copyright 1992 - 1998 Microsoft Corporation 
* 
\**************************************************************************/ 
#define UNICODE 
 
#include <windows.h> 
#include <commdlg.h> 
#include "uconvert.h" 
#include "install.h" 
 
 
 
 
 
 
/**************************************************************************\ 
*  Global variables. 
\**************************************************************************/ 
 
HANDLE hInst; 
 
/* declare global HWNDs for the child windows. 
*   They are created at WM_CREATE  of the main window. 
*   Also used in the "View" dialogs. 
*/ 
HWND hwndLabel0, hwndLabel1; 
HWND hwndName0, hwndName1; 
HWND hwndSize0, hwndSize1; 
HWND hwndCodePage0, hwndCodePage1; 
HWND hwndByteOrder0, hwndByteOrder1; 
HWND hwndButton0, hwndButton1; 
 
/* Global variables storing the source and destination "type" information. 
* 
* used to communicate between main wnd proc, and *OptionsProc. 
* 
* gTypeSource - stores the type interpretation of the source data 
*       (and implicitly the destination data.) 
*   TYPEUNKNOWN: indeterminant... not set. Can not do conversion. 
*   TYPEUNICODE: source unicode & destination giDestinationCodePage. 
*   TYPECODEPAGE: source giSourceCodePage & destination unicode. 
* 
* giSourceCodePage stores valid source code page iff gTypeSource == TRUE 
* giDestinationCodePage stores valid destination code page iff gTypeSource == FALSE 
* 
*/ 
int gTypeSource; 
UINT giSourceCodePage; 
UINT giDestinationCodePage; 
 
/* Pointers to the source and destination data, and the 
 *  count of bytes in each of the buffers. 
 */ 
#define NODATA 0 
PBYTE pSourceData =       NULL; 
PBYTE pDestinationData =  NULL; 
int   nBytesSource =      NODATA; 
int   nBytesDestination = NODATA; 
 
/* Conversion Options variables. */ 
DWORD gMBFlags = MB_PRECOMPOSED; 
DWORD gWCFlags = 0; 
 
char  glpDefaultChar[4] = "?"; 
BOOL  gUsedDefaultChar = FALSE; 
 
/* Handling the Byte Order Mark (BOM). 
* 
* If the input file begins with a BOM, then we know it is unicode, 
*  we skip over the BOM and decrement the size of data by SIZEOFBOM. 
* 
* 
* Before writing data that we know is unicode, write the szBOM string 
*  to the file. 
* 
* Notice that this means that the file sizes we show in the window 
*  do NOT include the BOM. 
*/ 
 
char szBOM[] = "\377\376";  // 0xFF, 0xFE  // leave off TEXT() macro. 
char szRBOM[] = "\376\377";  // 0xFF, 0xFE  // leave off TEXT() macro. 
#define SIZEOFBOM 2 
 
/* Title of main window */ 
TCHAR TitleMBToWC[]= TEXT("UConvert -- MultiByteToWideChar()"); 
TCHAR TitleWCToMB[]= TEXT("UConvert -- WideCharToMultiByte()"); 
TCHAR TitleUnknown[]= TEXT("UConvert."); 
 
/* file name of the online help file */ 
TCHAR szHelpPathName[] = TEXT("uconvert.HLP"); 
 
/* Strings used to fill onscreen windows. */ 
TCHAR szBlank[] = TEXT(""); 
 
/* MessageBox() strings and flags. */ 
TCHAR MBTitle[30]= TEXT(""); 
UINT  MBFlags = MB_OK | MB_ICONEXCLAMATION; 
 
 
/* misc. defines affecting size and placement of child windows */ 
#define BORDER    GetSystemMetrics (SM_CXFRAME)*4 
#define WHEIGHT   GetSystemMetrics (SM_CYMENU) 
 
 
 
/**************************************************************************\ 
* 
*  function:  WinMain() 
* 
* 
\**************************************************************************/ 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                     LPSTR lpCmdLine, int nCmdShow) 
{ 
    MSG    msg; 
    WNDCLASS  wc; 
    HWND   hwndMain; 
    HACCEL haccel; 
 
 
    UNREFERENCED_PARAMETER( lpCmdLine ); 
    UNREFERENCED_PARAMETER(  nCmdShow ); 
    hInst = hInstance; 
 
 
    /* Check for previous instance.  If none, then register class. */ 
    if (!hPrevInstance) { 
 
      wc.style = 0; 
      wc.lpfnWndProc = (WNDPROC)MainWndProc; 
 
      wc.cbClsExtra = 0; 
      wc.cbWndExtra = 0; 
      wc.hInstance = hInstance; 
      wc.hIcon = LoadIcon(hInstance, TEXT("uconvertIcon")); 
      wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
      wc.hbrBackground = GetStockObject (LTGRAY_BRUSH); 
      wc.lpszMenuName =  TEXT("uconvertMenu"); 
      wc.lpszClassName = TEXT("uconvert"); 
 
      if (!RegisterClass(&wc)) return (FALSE); 
 
    }  /* class registered o.k. */ 
 
 
    /* Create the main window.  Return false if CreateWindow() fails */ 
    hwndMain = CreateWindow( 
        TEXT("uconvert"), 
        TitleUnknown, 
        (WS_OVERLAPPEDWINDOW & ~(WS_THICKFRAME | WS_MAXIMIZEBOX)) | WS_VISIBLE, 
        CW_USEDEFAULT, 
        CW_USEDEFAULT, 
        512,  // Big enough for most of the text. 
        16*WHEIGHT, 
        NULL, NULL, hInst, NULL); 
 
    if (!hwndMain) return (FALSE); 
 
 
    /* Load the accelerator table that provides clipboard support. */ 
    haccel = LoadAccelerators (hInst, TEXT("uconvertAccel")); 
 
    LoadString(hInst,IDS_APP_WARNING,MBTitle,sizeof(MBTitle)); 
 
    /* Loop getting messages and dispatching them. */ 
    while (GetMessage(&msg, NULL, 0,0)) { 
      if (!TranslateAccelerator(hwndMain, haccel, &msg)) { 
        TranslateMessage(&msg); 
        DispatchMessage(&msg); 
      } 
    } 
 
    return (msg.wParam); 
} 
 
 
 
 
/**************************************************************************\ 
* 
*  function:  MainWndProc() 
* 
* 
* On WM_CREATE create all of the child windows. 
* On WM_DESTROY make sure that all dynamically allocated memory is freed. 
* On WM_PAINT, outline many of the child windows. 
* On WM_COMMAND, respond to the command messages properly. 
* 
\**************************************************************************/ 
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
 
 
/* misc. variables used in multiple messages cases. */ 
RECT clientrect; 
RECT rect; 
TCHAR buffer[50]; 
static TCHAR szFilter[MAX_PATH]; 
 
  switch (message) { 
 
    /**********************************************************************\ 
    *  WM_CREATE 
    * 
    * Create all of the child windows used on this main window. 
    *  Assign the HWNDs to the correct static variables. 
    * 
    \**********************************************************************/ 
    case WM_CREATE: { 
      GetClientRect (hwnd, &clientrect); 
 
      /* Create Source Windows. */ 
      CopyRect (&rect, &clientrect); 
      rect.right = (clientrect.right - clientrect.left) /2; 
      InflateRect (&rect, -2*BORDER, -BORDER); 
      createwindows(&rect, 
                   hwnd, 
                   &hwndLabel0, 
                   &hwndName0, 
                   &hwndSize0, 
                   &hwndCodePage0, 
                   &hwndByteOrder0, 
                   &hwndButton0); 
 
      /* Create Destination Windows. */ 
      CopyRect (&rect, &clientrect); 
      rect.left = (clientrect.right - clientrect.left) /2; 
      InflateRect (&rect, -2*BORDER, -BORDER); 
      createwindows(&rect, 
                   hwnd, 
                   &hwndLabel1, 
                   &hwndName1, 
                   &hwndSize1, 
                   &hwndCodePage1, 
                   &hwndByteOrder1, 
                   &hwndButton1); 
 
      /* fill in window information that is different for source/destination */ 
      SetWindowText (hwndLabel0, LoadResourceString(IDS_SOURCE)); 
      SetWindowText (hwndLabel1, LoadResourceString(IDS_DESTINATION)); 
 
      SetWindowText (hwndButton0, LoadResourceString(IDS_VIEW_SOURCE_BTN)); 
      SetWindowText (hwndButton1, LoadResourceString(IDS_VIEW_DESTINATION_BTN)); 
 
      SetWindowLong (hwndButton0, GWL_ID, BID_VIEWSOURCE      ); 
      SetWindowLong (hwndButton1, GWL_ID, BID_VIEWDESTINATION ); 
 
      gTypeSource = TYPEUNKNOWN; 
      giSourceCodePage =      GetACP();  // Just some reasonable initializer. 
      giDestinationCodePage = GetACP();  // Just some reasonable initializer. 
 
      /* initialize source & destination data correctly */ 
      SendMessage (hwnd, WM_COMMAND, MID_CLEARSOURCE,      0); 
      SendMessage (hwnd, WM_COMMAND, MID_CLEARDESTINATION, 0); 
 
      /* Build up the correct filter strings for OPENFILENAME structure 
       *  Do it here so that we only have to do it once. 
       */ 
      { 
        TCHAR *p; 
 
        p = szFilter; 
        lstrcpy (buffer,LoadResourceString(IDS_FILE_FILTER_SPEC1)); 
        lstrcpy (p,buffer); 
        p += lstrlen (buffer) +1; 
        lstrcpy (buffer,TEXT("*.*")); 
        lstrcpy (p,buffer); 
        p += lstrlen (buffer) +1; 
 
        lstrcpy (buffer,LoadResourceString(IDS_FILE_FILTER_SPEC2)); 
        lstrcpy (p,buffer); 
        p += lstrlen (buffer) +1; 
        lstrcpy (buffer,TEXT("*.txt")); 
        lstrcpy (p,buffer); 
        p += lstrlen (buffer) +1; 
 
        lstrcpy (buffer,LoadResourceString(IDS_FILE_FILTER_SPEC3)); 
        lstrcpy (p,buffer); 
        p += lstrlen (buffer) +1; 
        lstrcpy (buffer,TEXT("*.utf")); 
        lstrcpy (p,buffer); 
        p += lstrlen (buffer) +1; 
 
        lstrcpy (p,TEXT("\0")); 
      } 
    } break; /* end WM_CREATE */ 
 
 
 
    /**********************************************************************\ 
    *  WM_DESTROY 
    * 
    * Release the Online help, and free allocated memory if any. 
    \**********************************************************************/ 
    case WM_DESTROY: 
      WinHelp( hwnd, szHelpPathName, (UINT) HELP_QUIT, (DWORD) NULL ); 
      ManageMemory (MMFREE, MMSOURCE,      0, pSourceData); 
      ManageMemory (MMFREE, MMDESTINATION, 0, pDestinationData); 
      PostQuitMessage(0); 
    break; 
 
 
    /**********************************************************************\ 
    *  WM_CTLCOLOR* 
    * 
    * Set the background of the child controls to be gray here. 
    \**********************************************************************/ 
    case WM_CTLCOLORBTN: 
    case WM_CTLCOLORSTATIC: { 
      HDC hdc; 
 
      hdc = (HDC) wParam; 
      SetBkMode (hdc, TRANSPARENT); 
      return (LRESULT)GetStockObject (LTGRAY_BRUSH); 
    } break; 
 
 
 
 
    /**********************************************************************\ 
    *  WM_PAINT 
    * 
    * Simply draw the two vertical divider lines, and 3D frame the children. 
    * 
    \**********************************************************************/ 
    case WM_PAINT: { 
      HDC hdc; 
      PAINTSTRUCT ps; 
 
      hdc = BeginPaint(hwnd, &ps); 
      GetClientRect (hwnd, &clientrect); 
 
      /* draw vertical separator line in the center */ 
      rect.left = (clientrect.right - clientrect.left ) /2 -1; 
      rect.top = clientrect.top; 
      rect.right = rect.left +1;; 
      rect.bottom = clientrect.bottom; 
      FrameRect (hdc, &rect, GetStockObject (GRAY_BRUSH)); 
      SelectObject (hdc, GetStockObject (WHITE_PEN)); 
      MoveToEx (hdc, rect.right, rect.top, NULL); 
      LineTo (hdc,rect.right, rect.bottom); 
 
      /* draw 3D outlines of child windows. */ 
      framechildwindow (hdc, hwnd, hwndName0); 
      framechildwindow (hdc, hwnd, hwndSize0); 
      framechildwindow (hdc, hwnd, hwndCodePage0); 
      framechildwindow (hdc, hwnd, hwndByteOrder0); 
 
      framechildwindow (hdc, hwnd, hwndName1); 
      framechildwindow (hdc, hwnd, hwndSize1); 
      framechildwindow (hdc, hwnd, hwndCodePage1); 
      framechildwindow (hdc, hwnd, hwndByteOrder1); 
 
      /* underline the labels */ 
      underlinechildwindow (hdc, hwnd, hwndLabel0); 
      underlinechildwindow (hdc, hwnd, hwndLabel1); 
 
      EndPaint (hwnd, &ps); 
    } break; /* end WM_PAINT */ 
 
 
 
 
    /**********************************************************************\ 
    *  WMU_ADJUSTFORNEWSOURCE 
    * 
    * lParam - szName of source (file, clipboard, ...) 
    * 
    * global - nBytesSource 
    * 
    * "user message."  Set the text of the Source windows 
    \**********************************************************************/ 
    case WMU_ADJUSTFORNEWSOURCE: { 
      LPVOID szName; 
 
      szName = (LPVOID) lParam; 
 
      /* Set Window text appropriately */ 
      SetWindowText (hwndName0, szName); 
      wsprintf (buffer, LoadResourceString(IDS_BYTES), nBytesSource); 
      SetWindowText (hwndSize0, buffer); 
      SetWindowText (hwndByteOrder0, szBlank); 
 
      /* Clear the destination data if any to avoid user confusion. */ 
      SendMessage (hwnd, WM_COMMAND, MID_CLEARDESTINATION, 0); 
 
      /* Reset the "type strings" based on new gTypeSource. */ 
      SendMessage (hwnd, WMU_SETTYPESTRINGS, 0,0); 
    } break; 
 
 
 
 
    /**********************************************************************\ 
    *  WMU_SETTYPESTRINGS 
    * 
    * "user message."  Set the text of the "type" windows to reflect 
    *  the state stored in gTypeSource and gi*CodePage. 
    * 
    \**********************************************************************/ 
    case WMU_SETTYPESTRINGS: 
      switch (gTypeSource) { 
        case TYPEUNICODE: 
          SetWindowText (hwndCodePage0, TEXT("Unicode")); 
          wsprintf (buffer, LoadResourceString(IDS_CODE_PAGE), 
                  giDestinationCodePage); 
          SetWindowText (hwndCodePage1, buffer); 
          SetWindowText (hwnd, TitleWCToMB); 
        break; 
        case TYPECODEPAGE: 
          wsprintf (buffer, LoadResourceString(IDS_CODE_PAGE), 
                  giSourceCodePage); 
          SetWindowText (hwndCodePage0, buffer); 
          SetWindowText (hwndCodePage1, TEXT("Unicode")); 
          SetWindowText (hwnd, TitleMBToWC); 
        break; 
        case TYPEUNKNOWN: 
          SetWindowText (hwndCodePage0, szBlank); 
          SetWindowText (hwndCodePage1, szBlank); 
          SetWindowText (hwnd, TitleUnknown); 
        break; 
      } /* end switch gTypeSource */ 
    break; 
 
 
    /**********************************************************************\ 
    *  WM_INITMENU 
    * 
    * Manage the enabled state of all of the menus. 
    *  Notice that the button enabled state is taken care of in ManageMemory(). 
    * 
    * In general, this is dependent upon pSourceData & pDestinationData. 
    *  They are either NULL or non-NULL, and menu items are dependent upon 
    *  this state. 
    * 
    * One exception is the "Paste from Clipboard menu" which is enabled 
    *  conditional upon there being text data in the clipboard. 
    * 
    \**********************************************************************/ 
    case WM_INITMENU: 
 
      /* Adjust the "Paste from Clipboard menu" */ 
      OpenClipboard (hwnd); 
      if (IsClipboardFormatAvailable (CF_UNICODETEXT) || 
          IsClipboardFormatAvailable (CF_OEMTEXT) || 
          IsClipboardFormatAvailable (CF_TEXT)) 
        EnableMenuItem (GetMenu (hwnd),MID_PASTESOURCE,      MF_ENABLED); 
      else 
        EnableMenuItem (GetMenu (hwnd),MID_PASTESOURCE,      MF_GRAYED); 
      CloseClipboard (); 
 
 
      /* Adjust the source data dependent menus. */ 
      if (pSourceData != NULL) { 
        EnableMenuItem (GetMenu (hwnd),MID_SOURCEOPT,        MF_ENABLED); 
        EnableMenuItem (GetMenu (hwnd),MID_SWAPSOURCE,       MF_ENABLED); 
        EnableMenuItem (GetMenu (hwnd),MID_CLEARSOURCE,      MF_ENABLED); 
        EnableMenuItem (GetMenu (hwnd),MID_CONVERTNOW,       MF_ENABLED); 
        EnableMenuItem (GetMenu (hwnd),MID_CONVERSIONOPT,    MF_ENABLED); 
        EnableMenuItem (GetMenu (hwnd),MID_DESTINATIONOPT,   MF_ENABLED); 
      } else { 
        EnableMenuItem (GetMenu (hwnd),MID_SOURCEOPT,        MF_GRAYED); 
        EnableMenuItem (GetMenu (hwnd),MID_SWAPSOURCE,       MF_GRAYED); 
        EnableMenuItem (GetMenu (hwnd),MID_CLEARSOURCE,      MF_GRAYED); 
        EnableMenuItem (GetMenu (hwnd),MID_CONVERTNOW,       MF_GRAYED); 
        EnableMenuItem (GetMenu (hwnd),MID_CONVERSIONOPT,    MF_GRAYED); 
        EnableMenuItem (GetMenu (hwnd),MID_DESTINATIONOPT,   MF_GRAYED); 
      } 
 
 
      /* Adjust the destination data dependent menus. */ 
      if (pDestinationData != NULL) { 
        EnableMenuItem (GetMenu (hwnd),MID_SAVEAS,           MF_ENABLED); 
        EnableMenuItem (GetMenu (hwnd),MID_SWAPDESTINATION,  MF_ENABLED); 
        EnableMenuItem (GetMenu (hwnd),MID_COPYDESTINATION,  MF_ENABLED); 
        EnableMenuItem (GetMenu (hwnd),MID_CLEARDESTINATION, MF_ENABLED); 
      } else { 
        EnableMenuItem (GetMenu (hwnd),MID_SAVEAS,           MF_GRAYED); 
        EnableMenuItem (GetMenu (hwnd),MID_SWAPDESTINATION,  MF_GRAYED); 
        EnableMenuItem (GetMenu (hwnd),MID_COPYDESTINATION,  MF_GRAYED); 
        EnableMenuItem (GetMenu (hwnd),MID_CLEARDESTINATION, MF_GRAYED); 
      } 
 
    break; 
 
 
 
 
 
    /**********************************************************************\ 
    *  WM_COMMAND 
    * 
    * Just switch() on the command ID.  Notice that menu and button 
    *  command messages are treated the same. 
    * 
    \**********************************************************************/ 
    case WM_COMMAND: 
      switch (LOWORD(wParam)) { 
 
 
        /******************************************************************\ 
        *  WM_COMMAND, MID_OPEN 
        * 
        * Put up common dialog, try to open & read file. 
        *  Fill windows with correct text & fill pSourceData. 
        \******************************************************************/ 
        case MID_OPEN  : { 
          HANDLE hFile; 
          DWORD nBytesRead; 
          TCHAR szFile[MAX_PATH],szFileTitle[MAX_PATH]; 
 
          /* First set up the structure for the GetOpenFileName 
           *  common dialog. 
           */ 
          { 
            OPENFILENAME OpenFileName; 
            /* buffers for the file names. */ 
 
            wsprintf (szFile, szBlank); 
            wsprintf (szFileTitle, szBlank); 
 
 
            OpenFileName.lStructSize       = sizeof(OPENFILENAME); 
            OpenFileName.hwndOwner         = hwnd; 
            OpenFileName.hInstance         = (HANDLE) hInst; 
            OpenFileName.lpstrFilter       = szFilter; // built in WM_CREATE 
            OpenFileName.lpstrCustomFilter = NULL; 
            OpenFileName.nMaxCustFilter    = 0L; 
            OpenFileName.nFilterIndex      = 1L; 
            OpenFileName.lpstrFile         = szFile; 
            OpenFileName.nMaxFile          = MAX_PATH; 
            OpenFileName.lpstrFileTitle    = szFileTitle; 
            OpenFileName.nMaxFileTitle     = MAX_PATH; 
            OpenFileName.lpstrInitialDir   = NULL; 
            OpenFileName.lpstrTitle        = LoadResourceString(IDS_OPEN_FILE_TITLE); 
 
            OpenFileName.nFileOffset       = 0; 
            OpenFileName.nFileExtension    = 0; 
            OpenFileName.lpstrDefExt       = NULL; 
 
            OpenFileName.lCustData         = 0; 
            OpenFileName.lpfnHook          = NULL; 
            OpenFileName.lpTemplateName    = NULL; 
 
            OpenFileName.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST; 
 
            if (!GetOpenFileName(&OpenFileName)) return 0; 
          } 
 
 
          /* User has filled in the file information. 
           *  Try to open that file for reading. 
           */ 
          hFile = CreateFile(szFile, 
                       GENERIC_READ, 
                       0, 
                       NULL, 
                       OPEN_EXISTING, 
                       FILE_ATTRIBUTE_NORMAL, 
                       NULL); 
          if (hFile == INVALID_HANDLE_VALUE) { 
            MessageBox (hwnd, LoadResourceString(IDS_OPEN_FILE_FAILED), 
                    MBTitle, MBFlags); 
            return 0; 
          } 
 
 
          /* make sure file is not too big... i.e. > 2^32 
           *  If it is OK, write the file size in hwndSize0 
           */ 
          { 
            BY_HANDLE_FILE_INFORMATION bhfi; 
 
            GetFileInformationByHandle (hFile, &bhfi); 
            if (bhfi.nFileSizeHigh != 0) { 
              MessageBox (hwnd, LoadResourceString(IDS_FILE_TOO_BIG), 
                      MBTitle, MBFlags); 
              CloseHandle (hFile); 
              return 0; 
            } 
 
            nBytesSource= bhfi.nFileSizeLow; 
 
          } 
 
          /* Allocate space for string, including potential UNICODE_NULL */ 
          pSourceData = ManageMemory (MMALLOC, MMSOURCE, nBytesSource +2, pSourceData); 
          if (pSourceData == NULL) { 
            CloseHandle (hFile); 
            return 0; 
          } 
 
          if (nBytesSource < SIZEOFBOM) { 
              gTypeSource = TYPEUNKNOWN; 
              goto no_bom; 
          } 
 
          /* first read two bytes and look for BOM */ 
          if (!ReadFile (hFile, pSourceData,SIZEOFBOM, &nBytesRead, NULL)) { 
            MessageBox (hwnd, LoadResourceString(IDS_READFILE_FAILED), 
                    MBTitle, MBFlags); 
            CloseHandle (hFile); 
            pSourceData = ManageMemory (MMFREE, MMSOURCE, 0, pSourceData); 
            return 0; 
          } 
 
 
 
          /* If file begins with BOM, then we know the type, 
           *  we'll decrement the number of bytes by two, 
           *  and read the rest of the data. 
           */ 
          if (IsBOM (pSourceData)) { 
            gTypeSource = TYPEUNICODE; 
            nBytesSource -=SIZEOFBOM; 
 
          /* If file begins with Reverse BOM, then we know the type, 
           *  we'll decrement the number of bytes by two, 
           *  and read the rest of the data, and post a message so 
           *  that we know to swap the order later. 
           */ 
          } else if (IsRBOM (pSourceData)) { 
            gTypeSource = TYPEUNICODE; 
            nBytesSource -=SIZEOFBOM; 
            MessageBox (hwnd, LoadResourceString(IDS_SWAPPING_BYTE_ORDER), 
                    MBTitle, MBFlags); 
            PostMessage (hwnd, WM_COMMAND, MID_SWAPSOURCE, 0); 
 
          /* Oops, does not begin with BOM. 
           *  Reset file pointer, and read data. 
           */ 
          } else { 
            gTypeSource = TYPEUNKNOWN; 
            SetFilePointer (hFile, -SIZEOFBOM, NULL, FILE_CURRENT); 
          } 
 
          no_bom: 
 
 
          /* try to read all of it into memory */ 
          if (!ReadFile (hFile, pSourceData,nBytesSource, &nBytesRead, NULL)) { 
            MessageBox (hwnd, LoadResourceString(IDS_READFILE_FAILED), 
                    MBTitle, MBFlags); 
            CloseHandle (hFile); 
            pSourceData = ManageMemory (MMFREE, MMSOURCE, 0, pSourceData); 
            return 0; 
          } 
 
          CloseHandle (hFile); 
 
          /* If we don't know the file type at this point, 
           *  try to determine if it is unicode. 
           */ 
          if (gTypeSource == TYPEUNKNOWN) { 
            if (IsUnicode (pSourceData)) { 
              gTypeSource = TYPEUNICODE; 
              pSourceData[nBytesSource]   = 0;  // UNICODE_NULL 
              pSourceData[nBytesSource+1] = 0; 
            } else { 
              gTypeSource = TYPECODEPAGE; 
              pSourceData[nBytesSource] = 0; 
            } 
          } 
 
          SendMessage (hwnd, WMU_ADJUSTFORNEWSOURCE, 0, (LPARAM)szFile); 
 
 
 
        } break;  /* end case MID_OPEN */ 
 
 
 
        /******************************************************************\ 
        *  WM_COMMAND, MID_SAVEAS 
        * 
        * Put up common dialog, try to open file, and write data to it. 
        \******************************************************************/ 
        case MID_SAVEAS: { 
          HANDLE hFile; 
          DWORD nBytesRead; 
          TCHAR szFile[MAX_PATH],szFileTitle[MAX_PATH]; 
 
          if (nBytesDestination == NODATA ) { 
            MessageBox (hwnd, LoadResourceString(IDS_NOTEXT_TO_SAVE), 
                    MBTitle, MBFlags); 
            return 0; 
          } 
 
 
          /* Set up the structure for the GetSaveFileName 
           *  common dialog. 
           */ 
          { 
            OPENFILENAME OpenFileName; 
            /* buffers for the file names. */ 
 
            wsprintf (szFile, szBlank); 
            wsprintf (szFileTitle, szBlank); 
 
            OpenFileName.lStructSize       = sizeof(OPENFILENAME); 
            OpenFileName.hwndOwner         = hwnd; 
            OpenFileName.hInstance         = (HANDLE) hInst; 
            OpenFileName.lpstrFilter       = szFilter; 
            OpenFileName.lpstrCustomFilter = NULL; 
            OpenFileName.nMaxCustFilter    = 0L; 
            OpenFileName.nFilterIndex      = 1L; 
            OpenFileName.lpstrFile         = szFile; 
            OpenFileName.nMaxFile          = MAX_PATH; 
            OpenFileName.lpstrFileTitle    = szFileTitle; 
            OpenFileName.nMaxFileTitle     = MAX_PATH; 
            OpenFileName.lpstrInitialDir   = NULL; 
            OpenFileName.lpstrTitle        = LoadResourceString(IDS_SAVE_AS_TITLE); 
 
            OpenFileName.nFileOffset       = 0; 
            OpenFileName.nFileExtension    = 0; 
            OpenFileName.lpstrDefExt       = NULL; 
 
            OpenFileName.lCustData         = 0; 
            OpenFileName.lpfnHook          = NULL; 
            OpenFileName.lpTemplateName    = NULL; 
 
            OpenFileName.Flags = OFN_HIDEREADONLY; 
 
            if (!GetSaveFileName(&OpenFileName)) return 0; 
          } 
 
 
          /* User has filled in the file information. 
           *  Try to open that file for writing. 
           */ 
          hFile = CreateFile(szFile, 
                      GENERIC_WRITE, 
                      0, 
                      NULL, 
                      CREATE_ALWAYS, 
                      FILE_ATTRIBUTE_NORMAL, 
                      NULL); 
 
          if (hFile == INVALID_HANDLE_VALUE) { 
            MessageBox (hwnd, LoadResourceString(IDS_CREATEFILE_FAILED), 
                    MBTitle, MBFlags); 
            return 0; 
          } 
 
 
          /* if destination is unicode, try to write BOM first. 
           *  unless the bytes have been swapped 
           *  (criterion: hwndByteOrder contains text) 
           *  in which case, write a Reverse Byte Order Mark. 
           */ 
          if (gTypeSource == TYPECODEPAGE) { 
            if (GetWindowTextLength (hwndByteOrder1) == 0) { 
 
              if (!WriteFile (hFile, szBOM, SIZEOFBOM, &nBytesRead, NULL)) { 
                MessageBox (hwnd, LoadResourceString(IDS_WRITEFILE_FAILED), 
                        MBTitle, MBFlags); 
                CloseHandle (hFile); 
                return 0; 
              } 
 
            }else { 
              if (!WriteFile (hFile, szRBOM, SIZEOFBOM, &nBytesRead, NULL)) { 
                MessageBox (hwnd, LoadResourceString(IDS_WRITEFILE_FAILED), 
                        MBTitle, MBFlags); 
                CloseHandle (hFile); 
                return 0; 
              } 
 
            } 
          } 
 
 
          /* try to write all of it into memory */ 
          if (!WriteFile (hFile, pDestinationData,nBytesDestination, &nBytesRead, NULL)) { 
            MessageBox (hwnd, LoadResourceString(IDS_WRITEFILE_FAILED), 
                    MBTitle, MBFlags); 
            CloseHandle (hFile); 
            return 0; 
          } 
 
          SetWindowText (hwndName1, szFile); 
          CloseHandle (hFile); 
 
        } break; 
 
 
        /**********************************************************************\ 
        *  WM_COMMAND, MID_PASTESOURCE 
        * 
        * Paste the clipboard's prefered data format into the source. 
        *  Fills pSourceData. 
        \**********************************************************************/ 
        case MID_PASTESOURCE: { 
          UINT  iFormat; 
          PVOID pData; 
 
          OpenClipboard (hwnd); 
 
          iFormat = 0; 
          while (iFormat = EnumClipboardFormats(iFormat)) 
            if ((iFormat == CF_UNICODETEXT) || (iFormat == CF_OEMTEXT) || (iFormat == CF_TEXT)) { 
 
              HGLOBAL hMem; 
 
              hMem = GetClipboardData (iFormat); 
              pData = GlobalLock(hMem); 
 
              switch (iFormat) { 
                case CF_UNICODETEXT: 
                  nBytesSource = lstrlenW (pData) *2; 
                  pSourceData= ManageMemory (MMALLOC, MMSOURCE, nBytesSource+2, pSourceData); 
                  lstrcpyW ((LPVOID)pSourceData, pData); 
                  gTypeSource = TYPEUNICODE; 
                break; 
 
                case CF_OEMTEXT: 
                  nBytesSource = lstrlenA (pData); 
                  pSourceData= ManageMemory (MMALLOC, MMSOURCE, nBytesSource+1, pSourceData); 
                  lstrcpyA (pSourceData, pData); 
                  gTypeSource = TYPECODEPAGE; 
                  giSourceCodePage = GetOEMCP(); 
                break; 
 
                case CF_TEXT: 
                  nBytesSource = lstrlenA (pData); 
                  pSourceData= ManageMemory (MMALLOC, MMSOURCE, nBytesSource+1, pSourceData); 
                  lstrcpyA (pSourceData, pData); 
                  gTypeSource = TYPECODEPAGE; 
                  giSourceCodePage = GetACP(); 
                break; 
 
                default: break;  // shouldn't get here 
              } /* end switch (iFormat) */ 
 
              SendMessage (hwnd, WMU_ADJUSTFORNEWSOURCE, 0, 
(LPARAM)LoadResourceString(IDS_FROM_CLIPBOARD)); 
 
              GlobalUnlock(hMem); 
            break;  /* break out of while loop. */ 
            } /* end if iFormat */ 
 
 
          CloseClipboard (); 
 
        } break; 
 
 
 
        /**********************************************************************\ 
        *  WM_COMMAND, MID_COPYDESTINATION 
        * 
        * Copy destination data to the clipboard. 
        \**********************************************************************/ 
        case MID_COPYDESTINATION: 
        { 
          HGLOBAL hMem; 
          if (pDestinationData == NULL) return FALSE; 
 
          if (gTypeSource != TYPEUNICODE) { 
              if (!(hMem = GlobalAlloc( 
                      GMEM_MOVEABLE | GMEM_DDESHARE, 
                      (lstrlenW((LPWSTR)pDestinationData)+1) * 2))) { 
                  return FALSE; 
              } 
              lstrcpyW(GlobalLock(hMem), (LPWSTR)pDestinationData); 
              GlobalUnlock(hMem); 
          } else { 
              if (!(hMem = GlobalAlloc( 
                      GMEM_MOVEABLE | GMEM_DDESHARE, 
                      lstrlenA(pDestinationData)+1))) { 
                  return FALSE; 
              } 
              lstrcpyA(GlobalLock(hMem), pDestinationData); 
              GlobalUnlock(hMem); 
          } 
 
          OpenClipboard (hwnd); 
          EmptyClipboard(); 
 
          /* if source NOT unicode, then destination is, else look at dest CP */ 
          if (gTypeSource != TYPEUNICODE) 
            SetClipboardData (CF_UNICODETEXT, hMem); 
          else if (giDestinationCodePage == GetOEMCP()) 
            SetClipboardData (CF_OEMTEXT, hMem); 
          else 
            SetClipboardData (CF_TEXT, hMem); 
 
 
          CloseClipboard (); 
 
        break; 
        } 
 
 
 
        /******************************************************************\ 
        *  WM_COMMAND, MID_CONVERTNOW 
        * 
        * This is where the conversion actually takes place. 
        *  In either case, make the call twice.  Once to determine how 
        *  much memory is needed, allocate space, and then make the call again. 
        * 
        *  If conversion succeeds, it fills pDestinationData. 
        \******************************************************************/ 
        case MID_CONVERTNOW: { 
          int nBytesNeeded, nWCharNeeded, nWCharSource; 
 
 
          if (nBytesSource == NODATA ) { 
            MessageBox (hwnd, LoadResourceString(IDS_LOAD_SOURCE_FILE), 
                    MBTitle, MBFlags); 
            return 0; 
          } 
 
 
          /* Converting UNICODE -> giDestinationCodePage*/ 
          if (gTypeSource == TYPEUNICODE) { 
 
            nWCharSource = nBytesSource/2; 
 
            /* Query the number of bytes required to store the Dest string */ 
            nBytesNeeded = WideCharToMultiByte(giDestinationCodePage, gWCFlags, 
                             (LPWSTR)pSourceData, nWCharSource, 
                             NULL, 0, 
                             glpDefaultChar, &gUsedDefaultChar); 
 
            /* Allocate the required amount of space */ 
 
            if (nBytesNeeded == 0) { 
                MessageBox (hwnd, LoadResourceString(IDS_FIRSTCALL_FAILED), 
                        MBTitle, MBFlags); 
                break; 
            } 
 
            /* We need more 1 byte for '\0' */ 
            pDestinationData= ManageMemory (MMALLOC, MMDESTINATION, nBytesNeeded + 2, pDestinationData); 
 
            /* Do the conversion */ 
            nBytesDestination = WideCharToMultiByte(giDestinationCodePage, gWCFlags, 
                             (LPWSTR)pSourceData, nWCharSource, 
                             pDestinationData, nBytesNeeded, glpDefaultChar, &gUsedDefaultChar); 
            if (nBytesNeeded == 0) { 
                MessageBox (hwnd, LoadResourceString(IDS_FIRSTCALL_FAILED), 
                        MBTitle, MBFlags); 
                break; 
            } 
            *(LPSTR)((LPSTR)pDestinationData + nBytesNeeded) = '\0'; 
          } 
 
 
          /* converting giSourceCodePage -> UNICODE */ 
          else if (gTypeSource == TYPECODEPAGE) { 
 
            /* Query the number of WChar required to store the Dest string */ 
            nWCharNeeded = MultiByteToWideChar(giSourceCodePage, gMBFlags, 
                             pSourceData, nBytesSource, NULL, 0 ); 
 
            /* Allocate the required amount of space */ 
 
            /* We need more 2 bytes for '\0' */ 
            pDestinationData= ManageMemory (MMALLOC, MMDESTINATION, (nWCharNeeded+1)*2, pDestinationData); 
 
            /* Do the conversion */ 
            nWCharNeeded = MultiByteToWideChar(giSourceCodePage, gMBFlags, 
                             pSourceData, nBytesSource, 
                             (LPWSTR)pDestinationData, nWCharNeeded); 
 
            *(LPWSTR)((LPWSTR)pDestinationData + nWCharNeeded) = L'\0'; 
 
            /* MultiByteToWideChar returns # WCHAR, so multiply by 2 */ 
            nBytesDestination = 2*nWCharNeeded ; 
          } else { 
            MessageBox (hwnd, LoadResourceString(IDS_SOURCE_TYPE_UNKNOWN), 
                    MBTitle, MBFlags); 
            return 0; 
          } 
 
 
          /* code common to all conversions... */ 
          SetWindowText (hwndName1, LoadResourceString(IDS_DATA_NOT_SAVED)); 
          wsprintf (buffer, LoadResourceString(IDS_BYTES), nBytesDestination); 
          SetWindowText (hwndSize1, buffer); 
          SetWindowText (hwndByteOrder1, szBlank); 
 
 
          /* Throw up "Save as" dialog to help the user along. 
           *  They can always <esc> if need be. 
           */ 
          SendMessage (hwnd, WM_COMMAND, MID_SAVEAS, 0); 
 
        } break; /* end  case BID_CONVERT */ 
 
 
 
        /******************************************************************\ 
        *  WM_COMMAND, BID_VIEWSOURCE 
        * 
        \******************************************************************/ 
        case BID_VIEWSOURCE: 
          if (gTypeSource == TYPEUNICODE) 
            DialogBoxW (hInst, L"ShowTextDlg", hwnd, (DLGPROC)ViewSourceProc); 
          else 
            DialogBoxA (hInst, "ShowTextDlg", hwnd, (DLGPROC)ViewSourceProc); 
        break; 
 
        /******************************************************************\ 
        *  WM_COMMAND, BID_VIEWDESTINATION 
        * 
        \******************************************************************/ 
        case BID_VIEWDESTINATION: 
          if (gTypeSource == TYPEUNICODE) 
            DialogBoxA (hInst, "ShowTextDlg", hwnd, (DLGPROC)ViewDestinationProc); 
          else 
            DialogBoxW (hInst, L"ShowTextDlg", hwnd, (DLGPROC)ViewDestinationProc); 
        break; 
 
 
 
        /******************************************************************\ 
        *  WM_COMMAND, MID_SOURCEOPT 
        * 
        * Allows user to change interpretation options for the source data. 
        * 
        *  Put up appropriate dialog box, and reset window text in response. 
        \******************************************************************/ 
        case MID_SOURCEOPT: 
          if (DialogBox (hInst, TEXT("DataOptionsDlg"), hwnd, (DLGPROC)SourceOptionsProc)) { 
            SendMessage (hwnd, WMU_SETTYPESTRINGS, 0,0); 
            SendMessage (hwnd, WM_COMMAND, MID_CLEARDESTINATION, 0); 
          } 
        break; 
 
        /******************************************************************\ 
        *  WM_COMMAND, MID_DESTINATIONOPT 
        * 
        * Allows user to change options for destination data. 
        * 
        *  Put up appropriate dialog box, and reset window text in response. 
        \******************************************************************/ 
        case MID_DESTINATIONOPT: 
          if (DialogBox (hInst, TEXT("DataOptionsDlg"), hwnd, (DLGPROC)DestinationOptionsProc)) { 
            SendMessage (hwnd, WMU_SETTYPESTRINGS, 0,0); 
            SendMessage (hwnd, WM_COMMAND, MID_CLEARDESTINATION, 0); 
          } 
        break; 
 
        /******************************************************************\ 
        *  WM_COMMAND, MID_CONVERSIONOPT 
        * 
        \******************************************************************/ 
        case MID_CONVERSIONOPT: 
          if (DialogBox (hInst, TEXT("ConversionOptionsDlg"), hwnd, (DLGPROC)ConversionOptionsProc)) { 
            SendMessage (hwnd, WM_COMMAND, MID_CLEARDESTINATION, 0); 
          } 
        break; 
 
 
 
        /******************************************************************\ 
        *  WM_COMMAND, MID_SWAPSOURCE 
        * 
        * Allows user to reverse byte order of data. 
        * 
        \******************************************************************/ 
        case MID_SWAPSOURCE: { 
          int i, end; 
          BYTE temp; 
 
          if (pSourceData == NULL) return FALSE; 
 
          end =  nBytesSource - 2; 
          for (i = 0; i<= end; i+=2) { 
            temp             = pSourceData[i]; 
            pSourceData[i]   = pSourceData[i+1]; 
            pSourceData[i+1] = temp; 
          } 
 
          if (GetWindowTextLength (hwndByteOrder0) == 0) 
            SetWindowText (hwndByteOrder0, 
                    LoadResourceString(IDS_BYTE_ORDER_REVERSED)); 
          else 
            SetWindowText (hwndByteOrder0, szBlank); 
 
          /* Since source is different, invalidate Destination data. */ 
          SendMessage (hwnd, WM_COMMAND, MID_CLEARDESTINATION, 0); 
 
        } break; 
 
 
 
        /******************************************************************\ 
        *  WM_COMMAND, MID_SWAPDESTINATION 
        * 
        * Allows user to reverse byte order of data. 
        * 
        \******************************************************************/ 
        case MID_SWAPDESTINATION: { 
          int i, end; 
          BYTE temp; 
 
          if (pDestinationData == NULL) return FALSE; 
 
          end =  nBytesDestination - 2; 
          for (i = 0; i<= end; i+=2) { 
            temp             = pDestinationData[i]; 
            pDestinationData[i]   = pDestinationData[i+1]; 
            pDestinationData[i+1] = temp; 
          } 
 
          if (GetWindowTextLength (hwndByteOrder1) == 0) 
            SetWindowText (hwndByteOrder1, 
                    LoadResourceString(IDS_BYTE_ORDER_REVERSED)); 
          else 
            SetWindowText (hwndByteOrder1, szBlank); 
 
        } break; 
 
 
        /**********************************************************************\ 
        *  WM_COMMAND, MID_CLEARDESTINATION 
        * 
        * Clear the destination information.  May cause data to be lost. 
        \**********************************************************************/ 
        case MID_CLEARDESTINATION: 
          SetWindowText (hwndSize1, szBlank); 
          SetWindowText (hwndName1, szBlank); 
          SetWindowText (hwndByteOrder1, szBlank); 
          pDestinationData= ManageMemory (MMFREE, MMDESTINATION, 0, pDestinationData); 
        break; 
 
 
        /**********************************************************************\ 
        *  WM_COMMAND, MID_CLEARSOURCE 
        * 
        * Clear the SOURCE information.  May cause data to be lost. 
        \**********************************************************************/ 
        case MID_CLEARSOURCE: 
          SetWindowText (hwndSize0, szBlank); 
          SetWindowText (hwndName0, szBlank); 
          SetWindowText (hwndByteOrder0, szBlank); 
          pSourceData= ManageMemory (MMFREE, MMSOURCE, 0, pSourceData); 
        break; 
 
 
 
 
 
        /******************************************************************\ 
        *  WM_COMMAND, MID_INSTALLTABLES 
        * 
        \******************************************************************/ 
        case MID_INSTALLTABLES: 
          DialogBox (hInst, TEXT("InstallTableDlg"), hwnd, (DLGPROC)InstallTableProc); 
        break; 
 
 
 
 
        /* Simply call WinHelp to display the OnLine help file. */ 
        case MID_HELP: 
          WinHelp( hwnd, szHelpPathName, HELP_INDEX, (DWORD) NULL ); 
        break; 
 
 
        /* No-op Window procedure to simply display the dialog box. */ 
        case MID_ABOUT: 
          ShellAbout (hwnd, TEXT("UConvert"), NULL, LoadIcon (hInst, TEXT("uconvertIcon"))); 
        break; 
 
        /* Just close the window. */ 
        case MID_EXIT: 
          PostMessage (hwnd, WM_CLOSE, 0,0); 
        break; 
 
 
 
 
      } /* end switch (LOWORD(wParam)) */ 
    break;  /* end WM_COMMAND */ 
 
 
 
    default: break; 
  } /* end switch */ 
 
  return (DefWindowProc(hwnd, message, wParam, lParam)); 
} 
 
 
 
 
 
/**************************************************************************\ 
* 
*  function:  IsUnicode() 
* 
* HACK... eventually use a proper function for IsUnicode 
*  Use function from unipad? 
* 
\**************************************************************************/ 
BOOL IsUnicode (PBYTE pb) 
{ 
  return (IsBOM (pb)); 
} 
 
 
 
/**************************************************************************\ 
* 
*  function:  IsBOM() 
* 
* true iff pb points to a Byte Order Mark. 
* 
\**************************************************************************/ 
BOOL IsBOM (PBYTE pb) 
{ 
  if ((*pb == 0xFF) & (*(pb+1) == 0xFE))  // BOM 
    return TRUE; 
  else 
    return FALSE; 
} 
 
 
/**************************************************************************\ 
* 
*  function:  IsRBOM() 
* 
* true iff pb points to a reversed Byte Order Mark. 
* 
\**************************************************************************/ 
BOOL IsRBOM (PBYTE pb) 
{ 
  if ((*pb == 0xFE) & (*(pb+1) == 0xFF))  // RBOM 
    return TRUE; 
  else 
    return FALSE; 
} 
 
 
 
 
/**************************************************************************\ 
* 
*  function:  framechildwindow() 
* 
* Simply draw a 3D frame around child window. 
* 
\**************************************************************************/ 
VOID framechildwindow (HDC hdc, HWND hwndParent, HWND hwndChild) 
{ 
RECT rect; 
 
      GetWindowRect (hwndChild, &rect); 
 
      /* minor hack... assumes RECT is two points, right field starting first */ 
      ScreenToClient (hwndParent, (LPPOINT)&rect); 
      ScreenToClient (hwndParent, (LPPOINT)&(rect.right)); 
 
      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.right, rect.bottom); 
      LineTo (hdc,rect.left, rect.bottom); 
 
    return; 
} 
 
 
/**************************************************************************\ 
* 
*  function:  underlinechildwindow() 
* 
* Underline child window. 
* 
\**************************************************************************/ 
VOID underlinechildwindow (HDC hdc, HWND hwndParent, HWND hwndChild) 
{ 
RECT rect; 
 
      GetWindowRect (hwndChild, &rect); 
 
      /* minor hack... assumes RECT is two points, right field starting first */ 
      ScreenToClient (hwndParent, (LPPOINT)&rect); 
      ScreenToClient (hwndParent, (LPPOINT)&(rect.right)); 
 
      InflateRect (&rect, 1, 1); 
      rect.top = rect.bottom-1; 
      FrameRect (hdc, &rect, GetStockObject (GRAY_BRUSH)); 
      SelectObject (hdc, GetStockObject (WHITE_PEN)); 
      MoveToEx (hdc, rect.right, rect.bottom, NULL); 
      LineTo (hdc,rect.left, rect.bottom); 
 
    return; 
} 
 
 
 
 
 
 
 
/**************************************************************************\ 
* 
*  function:  createwindows() 
* 
* Create the child windows and pass the handles back in parameters. 
*  Each Window is created relative to (inside of) prect. 
*  top is a spacial pointer to the Y coordinate of the next window. 
* 
\**************************************************************************/ 
VOID createwindows(PRECT prect, 
                   HWND  hwndParent, 
                   HWND* hwndLabel, 
                   HWND* hwndName, 
                   HWND* hwndSize, 
                   HWND* hwndCodePage, 
                   HWND* hwndByteOrder, 
                   HWND* hwndButton) 
{ 
int top; 
 
  top = prect->top; 
  *hwndLabel = CreateWindow( 
          TEXT("STATIC"), 
          szBlank, 
          WS_CHILD | WS_VISIBLE | SS_CENTER, 
          prect->left, 
          top, 
          prect->right - prect->left, 
          WHEIGHT, 
          hwndParent, NULL, hInst, 0); 
 
  top += WHEIGHT*5/2; 
  *hwndName = CreateWindow( 
          TEXT("STATIC"), 
          szBlank, 
          WS_CHILD | WS_VISIBLE | SS_RIGHT, 
          prect->left, 
          top, 
          prect->right - prect->left, 
          WHEIGHT, 
          hwndParent, NULL, hInst, 0); 
 
  top += WHEIGHT*2; 
  *hwndSize = CreateWindow( 
          TEXT("STATIC"), 
          szBlank, 
          WS_CHILD | WS_VISIBLE | SS_LEFT, 
          prect->left, 
          top, 
          (prect->right - prect->left) *3/4, 
          WHEIGHT, 
          hwndParent, NULL, hInst, 0); 
 
  top += WHEIGHT*2; 
  *hwndCodePage = CreateWindow( 
          TEXT("STATIC"), 
          szBlank, 
          WS_CHILD | WS_VISIBLE | SS_LEFT, 
          prect->left, 
          top, 
          (prect->right - prect->left) *3/4, 
          WHEIGHT, 
          hwndParent, NULL, hInst, 0); 
 
  top += WHEIGHT*2; 
  *hwndByteOrder = CreateWindow( 
          TEXT("STATIC"), 
          szBlank, 
          WS_CHILD | WS_VISIBLE | SS_LEFT, 
          prect->left, 
          top, 
          (prect->right - prect->left) *3/4, 
          WHEIGHT, 
          hwndParent, NULL, hInst, 0); 
 
  top += WHEIGHT*2; 
  *hwndButton = CreateWindow( 
          TEXT("BUTTON"), 
          TEXT("ViewText"), 
          WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 
          prect->left, 
          top, 
          prect->right - prect->left, 
          WHEIGHT*9/7, 
          hwndParent, NULL, hInst, 0); 
 
  return; 
} 
 
 
/**************************************************************************\ 
* 
*  function:  ManageMemory() 
* 
* Do all memory management here for the source and destination pointers. 
*  We also enable/disable the "View..." buttons to reflect existence of data. 
* 
* 
* PARAMETERS 
* 
*  message : {MMALLOC, MMFREE} 
*    Alloc when requested by MMALLOC, and free the existing, passed in, pointer. 
*    Free when requested by MMFREE. 
*  sourcedestination : {MMSOURCE, MMDESTINATION} 
*  nBytes - number to alloc on MMALLOC messages. 
*  p - old pointer to be freed. 
* 
* 
* GLOBALS 
* 
*  hwndButton0, hwndButton1 
* 
\**************************************************************************/ 
LPVOID ManageMemory (UINT message, UINT sourcedestination, DWORD nBytes, LPVOID p) 
{ 
  switch (message) { 
    case MMFREE : 
      if (sourcedestination == MMSOURCE) 
        EnableWindow (hwndButton0, FALSE); 
      else if (sourcedestination == MMDESTINATION) 
        EnableWindow (hwndButton1, FALSE); 
 
      if (p != NULL) GlobalFree (GlobalHandle (p)); 
      return NULL; 
    break; 
 
    case MMALLOC : 
      if (sourcedestination == MMSOURCE) 
        EnableWindow (hwndButton0, TRUE); 
      else if (sourcedestination == MMDESTINATION) 
        EnableWindow (hwndButton1, TRUE); 
 
      if (p != NULL) GlobalFree (GlobalHandle (p)); 
      p = (LPVOID) GlobalAlloc (GPTR, nBytes); 
      return p; 
    break; 
 
  } /* end switch (message) */ 
  return NULL; 
} 
 
 
/**************************************************************************\ 
* 
*  function:  LoadResourceString() 
* 
*  Loads a resource string from string table and returns a pointer 
*  to the string. 
* 
*  PARAMETERS: wID - resource string id 
* 
\**************************************************************************/ 
LPTSTR LoadResourceString(UINT wID) 
{ 
    static TCHAR szBuf[512]; 
 
    LoadString((HANDLE)GetModuleHandle(NULL),wID,szBuf,sizeof(szBuf)); 
    return szBuf; 
}