CLIENT.C

/************************************************************************* 
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);
}