/*************************************************************************
                        Copyright Microsoft Corp. 1992-1996
                            Remote Machine WinType sample

    FILE        :   CLIENT.C

    PURPOSE     :   Client side of the RPC distributed application wintyp

    COMMENTS    :   This program shows the client side an application that
                    transfers a Windows datatype (HBITMAP) from the client
                    to the server, using Remote Procedure Calls. When the
                    Bitmap is received on the server end, it modifies the
                    bitmap, and sends it back.

                    Since this program uses the implicit binding method, 
                    some of the binding handling must be done at the 
                    client side.

*************************************************************************/
#include <windows.h>            // Required for all Windows programs
#include <commdlg.h>            // Support for the common dialogboxes

#include "common.h"             // Common headerfile for client and server
#include "client.h"             // Header file for the client
#include "clires.h"             // Definitions for the resource file
#include "wintyp.h"             // Generated by the MIDL compiler

TCHAR   szBuffer[200];          // Buffer used for printing messages

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//  Procedure   :   WinMain()
//  Desc.       :   Windows main procedure. Calls up the initialization 
//                  of the program , and starts up the message pump
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int WINAPI WinMain  (HINSTANCE  hInstance,
                     HINSTANCE  hPrevInstance,
                     LPSTR      lpszCmdLine,
                     int        nCmdShow)
{
    MSG         uMsg;           // The message struct
    HACCEL      hAccels;        // Handle to the accelerators
	
    // Set the global instance
    g_hInstance = hInstance;

    // Perform registration of the class and create the window
    if(!Init())
    {
        return FALSE;
    }
		
    // Display the window
    ShowWindow(g_hWnd, nCmdShow);
	
    // Load the accelerators
    hAccels = LoadAccelerators(hInstance,
        MAKEINTRESOURCE(IDR_ACCELERATOR1));

    // Add a message pump to take care of messages
    while (GetMessage(&uMsg, NULL, 0, 0))    // NULL only for WM_QUIT msg.
    {
        if(!TranslateAccelerator(g_hWnd, hAccels, &uMsg))
        {
            TranslateMessage(&uMsg);
            DispatchMessage(&uMsg);
        }
    }
    
    return uMsg.wParam;
}



//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Function :   Init()
// Purpose  :   This function is called once from the start of the program 
//              It will register the window class, create the window, and 
//              perform the binding to the server.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
BOOL Init()
{
    WNDCLASS    sWC;                        // The window class
    
    // Fill in the fields of the window class struct
    sWC.style = 0;                          // Style info
    sWC.lpfnWndProc  = (WNDPROC) ClientProc;// Proc. to handle messsages
    sWC.cbClsExtra   = 0;                   // Extra bytes for class
    sWC.cbWndExtra   = 0;                   // Extra bytes for window
    sWC.hInstance    = g_hInstance;         // Handle to current instance
    sWC.hIcon        = LoadIcon(g_hInstance,// Handle to icon for class
        MAKEINTRESOURCE(IDI_CLIENT_ICON));      
    sWC.hCursor      = LoadCursor(NULL, IDC_ARROW); // Handle to cursor 
    sWC.hbrBackground= GetStockObject(GRAY_BRUSH);  // Brush for backgr.
    sWC.lpszMenuName =
        MAKEINTRESOURCE(IDR_CLIENT_MENU);           // Name of menu to use
    sWC.lpszClassName= g_szClassName;               // Class name
    
    // Register the window class
    if(!RegisterClass(&sWC))
    {
        return FALSE;
    }

    // Create the window
    g_hWnd = CreateWindowEx(
        0,                      // Style
        g_szClassName,          // The class name
        g_szWindowCaption,      // Caption showed at top of window
        WS_OVERLAPPEDWINDOW,    // The window style
        CW_USEDEFAULT,          // x-coordinate
        CW_USEDEFAULT,          // y-coordinate
        CW_USEDEFAULT,          // Width of window
        CW_USEDEFAULT,          // Height of window
        NULL,                   // Parent window
        NULL,                   // Menu
        g_hInstance,            // Handle to current instance   
        NULL);                  // lpvParam
	
    // Return false if creation failed
    if(g_hWnd == NULL)
    {
        return FALSE;
    }

    // Initialize the binding address
    pszNetworkAddress[0] = 0;
    _tcscpy(pszEndpoint, END_POINT);
    _tcscpy(pszProtocolSequence, PROTOCOL_SEQUENCE);

    // Create the binding
    if(Bind(g_hWnd) != RPC_S_OK)
    {
        return FALSE;
    }

    return TRUE;                // Initialization OK
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Procedure    :   ClientWindowProc()
// Desc.        :   This procedure takes care of all the message handling 
//                  from the client main program
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
LRESULT CALLBACK    ClientProc(HWND   hWnd,
                               UINT    uMsg,
                               WPARAM  wParam,
                               LPARAM  lParam)
{
    PAINTSTRUCT sPS;                        // The paintstructure
    HDC         hDC = GetDC(g_hWnd);        // Handle to the screen
    HMENU       hMenu = GetMenu(g_hWnd);    // Handle to the menu
    RECT        sRect;
			
    switch(uMsg)
    {
        case WM_COMMAND :
		    switch(LOWORD(wParam))
            {
                case    IDM_MENU_FILE_OPEN  :       // File open was chosen
                    // Get the filename to read
                    if(GetBitmapFileName())
                    {
                        // Read the data from the file. This call will fill
                        // out the global variables g_hBitmap and g_Bitmap
                        if(!ReadBitmapFromFile())
                        {
                            break;
                        }
            
                        // Resize the client area to fit the image
                        GetWindowRect(g_hWnd, &sRect);
                        MoveWindow(g_hWnd,          // Handle to the window
                            sRect.left,             // New X position
                            sRect.top,              // New Y position
                            g_Bitmap.bmWidth +      // New width
                            GetSystemMetrics(SM_CXSIZEFRAME) * 2,
                            g_Bitmap.bmHeight +     // The new height
                            GetSystemMetrics(SM_CYSIZEFRAME) * 2 +
                            GetSystemMetrics(SM_CYMENUSIZE) +   
                            GetSystemMetrics(SM_CYCAPTION),     
                            TRUE);                  // Make a repaint

                        // Force an update of the screen
                        GetClientRect(g_hWnd, &sRect);
                        InvalidateRect(g_hWnd, &sRect, TRUE);
                        UpdateWindow(g_hWnd);

                        // Enable the rest of the menu options
                        EnableMenuItem(hMenu, IDM_MENU_FILE_CLOSE, 
                            MF_ENABLED);
                        if(GetDeviceCaps(hDC, BITSPIXEL) == 8)
                        {
                            EnableMenuItem(hMenu, IDM_MENU_TOOLS_EDGE, 
                                MF_ENABLED);
                        }
                        EnableMenuItem(hMenu, IDM_MENU_TOOLS_FLIP, 
                            MF_ENABLED);
                    }   // if(GetBitmapFileName())
                    break;
				
                case    IDM_MENU_FILE_CLOSE :   // File close was chosen
                    // If a bitmap has been read in, redraw the client 
                    // area to the background color.
                    if(BITMAP_READ)
                    {
                        // Reset the BITMAP_READ indicator
                        BITMAP_READ = FALSE;

                        // Rewrite the screen
                        RedrawClientArea(hDC);
								
                        // Disable the menu options
                        EnableMenuItem(hMenu, IDM_MENU_FILE_CLOSE,
                            MF_GRAYED);
                        EnableMenuItem(hMenu, IDM_MENU_TOOLS_EDGE,
                            MF_GRAYED);
                        EnableMenuItem(hMenu, IDM_MENU_TOOLS_FLIP,
                            MF_GRAYED);

                        // Delete the bitmap object
                        DeleteObject(g_hBitmap);		
                    }				
                    break;

                case    IDM_MENU_FILE_EXIT  :   // Exit program was chosen
                    PostMessage(g_hWnd, WM_CLOSE, 0, 0);
                    break;

                case    IDM_MENU_TOOLS_EDGE :   // Want to find edges 
                    if (!EDGE_FOUND)
                    {
                        ChangeBitmapRemote(FINDEDGE, &g_hBitmap);
                        RedrawClientArea(hDC);
                        EDGE_FOUND = TRUE;
                    }
                    break;

                case    IDM_MENU_TOOLS_FLIP :   // Want to flip the bitmap
                    ChangeBitmapRemote(FLIPIMAGE, &g_hBitmap);
                    RedrawClientArea(hDC);
                    break;

                case    IDM_MENU_FILE_BINDING:      // Binding dialog box
                    DialogBox(g_hInstance,
                        MAKEINTRESOURCE(IDD_BINDING_DIALOG),
                        hWnd,
                        (DLGPROC) BindingDlgProc);
                    break;

                case    IDM_MENU_ABOUT      :       // About dialog box
                    DialogBox(g_hInstance,
                        MAKEINTRESOURCE(IDD_ABOUT_DIALOG),
                        hWnd,
                        (DLGPROC) AboutDlgProc);
                    break;
            }
            break;

        case WM_PAINT :
            BeginPaint(g_hWnd, &sPS);    // Gets a device context
            RedrawClientArea(sPS.hdc);   // Redraws the screen
            EndPaint(g_hWnd, &sPS);      // Releases a device context
            break;

        case WM_CLOSE   :               // User requests windows closure
            ShutDown();                 // Shut down the server
            CleanUp();                  // Deallocate some memory
            DestroyWindow(hWnd);        // Generates the WM_DESTROY message
            break;

        case WM_DESTROY :
            PostQuitMessage(0);         // Puts a WM_QUIT in the queue
            break;                      // => GetMessage returns NULL

        default :
            ReleaseDC(g_hWnd, hDC);
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
	
    ReleaseDC(g_hWnd, hDC);
    return (0L);
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Procedure    :   void GetBitMapFileName(void)
// Desc.        :   This procedure calls the common dialog box 
//                  GetFileNameOpen to get the filename of a bitmap file
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
BOOL GetBitmapFileName(void)
{
	OPENFILENAME    sOfn;       // The OPENFILENAME struct
	
	// Variable used to filter out only the files needed
	LPCTSTR szFilter[] = {TEXT("Windows Bitmaps (*.bmp)"), TEXT("*.bmp"),
                         TEXT("")};

	// Fill in the OPENFILENAME Structure
	sOfn.lStructSize         = sizeof(OPENFILENAME);
	sOfn.hwndOwner           = g_hWnd;
	sOfn.hInstance           = g_hInstance;
	sOfn.lpstrFilter         = *szFilter;
	sOfn.lpstrCustomFilter   = NULL;
	sOfn.nMaxCustFilter      = 0;
	sOfn.nFilterIndex        = 0;            
	sOfn.lpstrFile           = g_szFileName; 
	sOfn.nMaxFile            = _MAX_PATH;    
	sOfn.lpstrFileTitle      = NULL;
	sOfn.nMaxFileTitle       = _MAX_FNAME + _MAX_EXT;
	sOfn.lpstrInitialDir     = NULL;         
	sOfn.lpstrTitle          = NULL;
	sOfn.Flags               = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
	sOfn.nFileOffset         = 0;
	sOfn.nFileExtension      = 0;
	sOfn.lpstrDefExt         = TEXT("bmp");
	sOfn.lCustData           = 0L;
	sOfn.lpfnHook            = NULL;
	sOfn.lpTemplateName      = NULL;
    
    // This function call will display a Open File dialog box, and read 
    // the name into the the global varaible g_szFileName. It will return
    // TRUE if a filename was chosen, and OK button clicked, else it will 
    // return FALSE
    return GetOpenFileName(&sOfn);
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Procedure    :   ReadBitmapFromFile()
// Desc.        :   This procedure reads a bitmap from a file and sets the
//                  global variables g_Bitmap and g_hBitmap.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
BOOL ReadBitmapFromFile(void)
{
    UINT    uLoadFlags;
    HDC     hDC = GetDC(g_hWnd);

    // Read in the palette from the file. Must do this first, because this
    // procedure checks for valid fileformats
    g_hPalette = LoadPaletteFromFile(g_szFileName);

    // If a file has already been read, get rid of that bitmap
    if (BITMAP_READ)
    {
        DeleteObject(g_hBitmap);
        BITMAP_READ = FALSE;
    }

    // Load image as a DIB image if its a 256 color image and the screen
    // resolution is in 256 colors
    if(g_BitsPerPixel == 8 && GetDeviceCaps(hDC, BITSPIXEL) == 8)
    {
        uLoadFlags = LR_LOADFROMFILE | LR_CREATEDIBSECTION;
    }
    else
    {
        uLoadFlags = LR_LOADFROMFILE;
    }

    // Load the bitmap image in from the global filename found with the
    // GetFileNameOpen common dialogbox
    g_hBitmap = (HBITMAP) LoadImage(
        NULL,                   // Want to load bitmap from file
        g_szFileName,           // Filename where bitmap is stored
        IMAGE_BITMAP,           // Type of image to be loaded
        0, 0,                   // The desired width and height
        uLoadFlags);
    
    // If the reading failed
    if (g_hBitmap == 0)
    {
        return FALSE;
    }
    
    // Obtain the infornation about the bitmap, from the handle returned
    // by the LoadImage function. Must delete this object before quitting
    GetObject(g_hBitmap, sizeof(BITMAP),(LPVOID) &g_Bitmap);

    BITMAP_READ = TRUE;         // Let PAINT know what to repaint
    EDGE_FOUND = FALSE;         // Not found the edges in this image yet

    return TRUE;
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Procedure    :   BOOL CALLBACK AboutDlgProc()
// Desc.        :   This procedure is called when the user chooses the
//                  About menu. It displays a Dialogbox defined in the 
//                  client.rc file and returns when the user clicks on the 
//                  OK button
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
BOOL CALLBACK AboutDlgProc(HWND hDlg, 
                           UINT uMsg, 
                           WPARAM wParam, 
                           LPARAM lParam)
{
    switch(uMsg)
    {
        case WM_INITDIALOG :            // Return TRUE, windows sets the
            return TRUE;                // focus on the OK button

        case WM_COMMAND :
            switch(LOWORD(wParam))
            {
                case IDOK:              // If the user clicks the OK button
                    EndDialog(hDlg, 0); // Take the dialogbox away
                    return TRUE;
            }
        default:
            return FALSE;           // Windows should handle the message
  }
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Procedure    :   BOOL CALLBACK BindingDlgProc()
// Desc.        :   This procedure is called when the user chooses Server 
//                  from the File menu. It displays a dialogbox defined in
//                  the client.rc file. Here the user can enter a specific
//                  binding to a remote server by specifying the network - 
//                  protocol and the endpoint to use, and the name of the 
//                  machine that runs the server program.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
BOOL CALLBACK BindingDlgProc(HWND hDlg, 
                             UINT uMsg, 
                             WPARAM wParam, 
                             LPARAM lParam)
{
    switch (uMsg) 
    {
        case WM_INITDIALOG:
            // Fill in the edit boxes with the current values
            SetDlgItemText((HANDLE)hDlg, IDC_PROTSEQ_NAME, 
                pszProtocolSequence);
            SetDlgItemText((HANDLE)hDlg, IDC_ENDPOINT_NAME, pszEndpoint);
            SetDlgItemText((HANDLE)hDlg, IDC_SERVER_NAME, 
                pszNetworkAddress);
            return(TRUE);

        case WM_COMMAND:   
            switch(LOWORD(wParam)) 
            {
                case IDCANCEL:     // Cancel button clicked
                    EndDialog(hDlg, FALSE);
                    return(TRUE);

                case IDOK:         // OK button clicked
                    GetDlgItemText(hDlg, IDC_PROTSEQ_NAME, 
                        pszProtocolSequence, 30);
                    GetDlgItemText(hDlg, IDC_SERVER_NAME, 
                        pszNetworkAddress, 30);
                    GetDlgItemText(hDlg, IDC_ENDPOINT_NAME, 
                        pszEndpoint, 30);

                    // If we get a binding, all is OK
                    if (Bind(hDlg) == RPC_S_OK) 
                    {
                        EndDialog(hDlg, FALSE);
                        return(TRUE);
                    }
                    // If we couldn't bind, just keep asking for new input
            }   // switch((LOWORD(WPARAM))
    }   // switch(uMsg)

    return(FALSE);  // Didn't process a message
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Procedure    :   RedrawClientArea(HDC)
// Desc.        :   This procedure redraw the client area by either 
//                  displaying the bitmap, or simply drawing a gray 
//                  background.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void RedrawClientArea(HDC hDC)                // Handle to the screen
{
    HDC     hDCMem;         // A memory device context
    RECT    sRect;          // Rectangle containing the entire client area

    // Do a check to see if the bitmap has been read in. If it hasn't, we 
    // leave the screen blank
    if(BITMAP_READ)
    {
        if(g_BitsPerPixel == 8 && g_hPalette != 0)
        {
            // Select and realize the palette to use
            SelectPalette(hDC, g_hPalette, TRUE);
            RealizePalette(hDC);
        }
			
        hDCMem = CreateCompatibleDC(hDC);
        SelectObject (hDCMem, g_hBitmap);
        SetMapMode (hDCMem, GetMapMode(hDC));

        // Draw the bitmap using the BitBlt function
        if(BitBlt(
            hDC,                // The destination device context
            0, 0,               // Coordinates of the destination rectangle
            g_Bitmap.bmWidth,   // Width of the dest. and source rectangle
            g_Bitmap.bmHeight,	// Height of the dest. and source rectangle
            hDCMem,
            0, 0,
            SRCCOPY))
        {
            DeleteDC(hDCMem);
        }
    }
    else        // We want to wipe the screen with the background color
    {
        GetClientRect(g_hWnd,  &sRect);
        FillRect(hDC, &sRect, GetStockObject(GRAY_BRUSH));
    }
    return;
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Funciton     :   LoadPaletteFromFile
// Desc.        :   This procedure loads a palette froma dib-file. It 
//                  checks to see that this is a 256-color image, and
//                  then reads in the palette, and returns a handle
//                  to it
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
HPALETTE LoadPaletteFromFile(LPTSTR lpszFileName)
{
    HANDLE              hFile;          // Bitmap filename
    HPALETTE            hPalette;       // Handle to the palette
    HANDLE              hMem,           // A handle to a memory location
                        hCore;          // Handle to memory
    DWORD               dwBitmapType,   // The type of the bitmap
                        dwSize;         // A size of memory to allocate
    int                 nIdx,           // Index in loops
                        nPalEntries;    // # of entries in the palette
    LPSTR               lpCore;         // Pointer to memory bytes
    LPLOGPALETTE        lpMem;          // A mem pointer to the LOGPALETTE
    BITMAPFILEHEADER    sBFH;           // This is always filled in
    BITMAPINFOHEADER    sBIH;           // Used if this is a Windows bitmap
    BITMAPCOREHEADER    sBCH;           // Used if this is a OS/2 bitmap
    DWORD               dwDummy;

    // Initialize the palette handle to NULL
    hPalette = NULL;

    // Open the file where the bitmap is stored
    hFile = CreateFile(
        lpszFileName, 
        GENERIC_READ, 
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        0);
    if(hFile != 0)
    {
        // Read the BITMAPFILEHEADER from the file
        if (ReadFile(hFile, &sBFH,sizeof(BITMAPFILEHEADER), 
            &dwDummy, NULL))
        {
            // Any valid bitmap file should have filetype = 'BM'
            if(sBFH.bfType == (UINT)0x4D42)
            {
                // Determine type of bitmap.
                // The next WORD (4 bytes) in the file (offset 14) will be
                // either 40 - indicating that this is a Windows Bitmap, 
                // and therefore will be using a BITMAPINFOHEADER, or it 
                // will be 14 - indicating that this is a OS/2 1.x bitmap,
                // and therefore will be using a BITMAPCOREHEADER. 14 and 
                // 40 are the respective sizes of the HEADERS
                ReadFile(hFile, &dwBitmapType, sizeof(DWORD), 
                    &dwDummy, NULL);
                SetFilePointer(hFile,sizeof(BITMAPFILEHEADER),
                    NULL, FILE_BEGIN);
	
                // Load up INFO header.  If bitmap is a CORE
                // header, then we need to convert to INFO header.
                if(dwBitmapType == sizeof(BITMAPCOREHEADER))
                {
                    // Read in the COREHEADER
                    ReadFile(hFile, &sBCH,sizeof(BITMAPCOREHEADER), 
                        &dwDummy, NULL);
                
                    // Fill out the missing parts of the INFOHEADER
                    sBIH.biSize          = sizeof(BITMAPINFOHEADER);
                    sBIH.biWidth         = sBCH.bcWidth;
                    sBIH.biHeight        = sBCH.bcHeight;
                    sBIH.biPlanes        = sBCH.bcPlanes;
                    sBIH.biBitCount      = sBCH.bcBitCount;
                    sBIH.biCompression   = BI_RGB;
                    sBIH.biSizeImage     = 0;
                    sBIH.biXPelsPerMeter = 0;
                    sBIH.biYPelsPerMeter = 0;
                    sBIH.biClrUsed       = 0;
                    sBIH.biClrImportant  = 0;
                }
                else
                {
                    // Read in the INFOHEADER
                    ReadFile(hFile, &sBIH,sizeof(BITMAPINFOHEADER), 
                        &dwDummy, NULL);
                }

                //-------------------------
                // Palette creation
                //-------------------------

                // Figure out the number of entries in the palette
                // i.e. if the number of Bits per pixel (biBitCount) is 8,
                // the number of palette entries will be 1 << 8 = 256
                nPalEntries = ((UINT)1 << sBIH.biBitCount);
                g_BitsPerPixel = sBIH.biBitCount;
       
                // Determine the size of the memory to allocate 
                // (The size of all mem needed for the palette)
                dwSize   = sizeof(LOGPALETTE) + 
                    (nPalEntries * sizeof(PALETTEENTRY));

                // Aloocate space for the palette. this just returns a 
                // handle to the memory. We must use the function 
                // GlobalLock to get a pointer to the memory
                if(hMem = GlobalAlloc(GHND,dwSize))
                {
                    // Extract a pointer to the memory just allocated, and
                    // cast it as a pointer to a LOGPALETTE struct
                    if(lpMem = (LPLOGPALETTE)GlobalLock(hMem))
                    {
                        // Set LogPalette structure.
                        lpMem->palVersion    = 0x0300;
                        lpMem->palNumEntries = nPalEntries;

                        // Read in ColorTable. COREHEADER files uses the 
                        // RGB triplet to store the values of the palette
                        if(dwBitmapType == sizeof(BITMAPCOREHEADER))
                        {
                            // Calculate the size of color map
                            dwSize = (nPalEntries * sizeof(RGBTRIPLE));

                            // Allocate memory to store this in
                            if(hCore = GlobalAlloc(GHND,dwSize))
                            {
                                // Get a pointer to the memory,and LOCK it
                                if(lpCore = GlobalLock(hCore))
                                {
                                    // Read the palette data into memory
                                    ReadFile(hFile, lpCore, dwSize, 
                                        &dwDummy, NULL);
    
                                    // Put the palette data into the 
                                    // palette struct
                                    for(nIdx=0; nIdx < nPalEntries; nIdx++)
                                    {
                                        lpMem->palPalEntry[nIdx].peBlue  = 
                                            (((RGBTRIPLE FAR * )lpCore) + nIdx)->rgbtBlue;
                                        lpMem->palPalEntry[nIdx].peGreen = 
                                            (((RGBTRIPLE FAR * )lpCore)+nIdx)->rgbtGreen;
                                        lpMem->palPalEntry[nIdx].peRed   = 
                                            (((RGBTRIPLE FAR * )lpCore)+nIdx)->rgbtRed;
                                        lpMem->palPalEntry[nIdx].peFlags = 0;
                                    }

                                    // Unlock the memory used
                                    GlobalUnlock(hCore);
                                }

                                // Free up the memory used
                                GlobalFree(hCore);
                            }
                        }
                        else
                        {
                            // The INFOHEADER version of a bitmap file uses
                            // RGB Quads to store the color map
                            dwSize = (nPalEntries * sizeof(RGBQUAD));

                            // Allocate memory to store this in
                            if(hCore = GlobalAlloc(GHND,dwSize))
                            {
                                // Get a pointer to the memory,and LOCK it
                                if(lpCore = GlobalLock(hCore))
                                {
                                    // Read the palette data into memory
                                    ReadFile(hFile, lpCore,dwSize, 
                                        &dwDummy, NULL);

                                    // Put the palette data into the 
                                    // palette struct
                                    for(nIdx=0; nIdx < nPalEntries; nIdx++)
                                    {
                                        lpMem->palPalEntry[nIdx].peBlue  = 
                                            (((LPRGBQUAD)lpCore)+nIdx)->rgbBlue;
                                        lpMem->palPalEntry[nIdx].peGreen = 
                                            (((LPRGBQUAD)lpCore)+nIdx)->rgbGreen;
                                        lpMem->palPalEntry[nIdx].peRed   = 
                                            (((LPRGBQUAD)lpCore)+nIdx)->rgbRed;
                                        lpMem->palPalEntry[nIdx].peFlags = 0;
                                    }
									
                                    // UNLOCK the data just used
                                    GlobalUnlock(hCore);
                                }

                                // Free up the memory used to store the 
                                // palette data
                                GlobalFree(hCore);
                            }
                        }

                        // Create a handle to the palette
                        hPalette = CreatePalette(lpMem);

                        // Unlock the memory used for storing the data to
                        // the LOGPALETTE
                        GlobalUnlock(hMem);
                    }

                    // Free up the memory used by the LOGPALETTE structure
                    GlobalFree(hMem);
                }
            }
        }
        else		// This is NOT a bitmap file
        {					
            PRINT(TEXT("This is not a BITMAP file"), 
                TEXT("Invalid Fileformat"));
            return FALSE;
        }


        // Close the file we have been reading from
        CloseHandle(hFile);
    }

    // Return the handle to the palette to the calling structure
    return(hPalette);
}



//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Procedure    :   RPC_STATUS Bind(HWND)
// Desc.        :   This procedure will make RPC API calls to bind to the 
//                  server application.
//                  The binding calls are made from Init() and whenever
//                  the user changes the server name or endpoint. If the 
//                  bind operation is successful, the global flag fBound 
//                  is set to TRUE. The global flag fBound is used to 
//                  determine whether to call the RPC API function 
//                  RpcBindingFree.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
RPC_STATUS Bind(HWND hWnd)
{
    RPC_STATUS nStatus;
    
    if (g_bBound == TRUE)     // unbind only if bound
    {  
        nStatus = RpcStringFree(&pszStringBinding);
        if (nStatus) 
        {
            _stprintf(szBuffer,TEXT("RpcStringFree failed 0x%x"), nStatus);
            MessageBox(hWnd,
                       szBuffer,
                       TEXT("RPC Sample Application"),
                       MB_ICONSTOP);
            return(nStatus);
        }

        nStatus = RpcBindingFree(&global_wintyp_sample_handle);
        if (nStatus) 
        {
            _stprintf(szBuffer,TEXT("RpcBindingFree failed 0x%x"), nStatus);
            MessageBox(hWnd,
                       szBuffer,
                       TEXT("RPC Sample Application"),
                       MB_ICONSTOP);
            return(nStatus);
        }

        g_bBound = FALSE;  // unbind successful; reset flag
    }

    nStatus = RpcStringBindingCompose(pszUuid,
                                     pszProtocolSequence,
                                     pszNetworkAddress,
                                     pszEndpoint,
                                     pszOptions,
                                     &pszStringBinding);
    if (nStatus) 
    {
        _stprintf(szBuffer, 
            TEXT("RpcStringBindingCompose returned : (0x%x)\nNetwork Address = %s\n"),
            nStatus, pszNetworkAddress);
        MessageBox(hWnd, szBuffer, TEXT("RPC Sample Application"), 
            MB_ICONINFORMATION);
        return(nStatus);
    }

    nStatus = RpcBindingFromStringBinding(pszStringBinding,
                            &global_wintyp_sample_handle);
    if (nStatus) 
    {
        _stprintf(szBuffer, 
            TEXT("RpcBindingFromStringBinding returned: (0x%x)\nString = %s\n"),
             nStatus, pszStringBinding);
        MessageBox(hWnd, szBuffer, TEXT("RPC Sample Application"), 
            MB_ICONINFORMATION);
        return(nStatus);
    }

    g_bBound = TRUE;  // bind successful; reset flag

    return(nStatus);
}

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Procedure    :   CleanUp()
// Desc.        :   This procedure deletes the object, and the memory used
//                  in the program.
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void CleanUp(void)
{
    // Destroy the object used for the bitmap
    DeleteObject(g_hBitmap);

    // Delete the space taken up by the binding 
    if (g_bBound)
    {
        status = RpcStringFree(&pszStringBinding);
        if (status) 
        {
            _stprintf(szBuffer,TEXT("RpcStringFree failed 0x%x"), status);
            MessageBox(g_hWnd,
                       szBuffer,
                       TEXT("RPC Sample Application"),
                       MB_ICONSTOP);
            exit(EXECUTION_FAILED);
        }

        status = RpcBindingFree(&global_wintyp_sample_handle);
        if (status) 
        {
            _stprintf(szBuffer,TEXT("RpcBindingFree failed 0x%x"), status);
            MessageBox(g_hWnd,
                       szBuffer,
                       TEXT("RPC Sample Application"),
                       MB_ICONSTOP);
            exit(EXECUTION_FAILED);
        }
    }
}


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Procedure    :   midl_user_allocate() and midl_user_free()           
// Desc.        :   These procedure are declared in the header file     
//                  generated by the midl compiler. These procedures    
//                  should be used for all memory allocation and        
//                  deallocation.                                       
//                  These procedures are also called by the stub code to
//                  allocate and free memory.                           
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
void __RPC_FAR * __RPC_API midl_user_allocate(size_t nLen)
{
    return (malloc(nLen));
}

void __RPC_API midl_user_free(void __RPC_FAR * lpvPointer)
{
    if(NULL != lpvPointer)
        free (lpvPointer);
}
