HELLCTRL.CPP
/************************************************************************* 
** 
**    Automation Controller that uses vtable binding. 
**    Controls the HELLO automation object. 
** 
**    hellctrl.cpp 
** 
** 
**     Written by Microsoft Product Support Services, Windows Developer Support 
**    (c) Copyright Microsoft Corp. 1994 - 1996 All Rights Reserved 
** 
*************************************************************************/ 
#define STRICT 
 
#include <windows.h> 
#include <windowsx.h> 
#ifdef WIN16    
  #include <ole2.h> 
  #include <compobj.h>     
  #include <dispatch.h>  
  #include <variant.h> 
  #include <olenls.h> 
  #include <commdlg.h>   
#endif   
#include <initguid.h>    
#include "tlb.h"  
#include "hellctrl.h"       
 
// Globals 
HINSTANCE g_hinst;                          // Instance of application 
HWND      g_hwnd;                           // Toplevel window handle 
 
// String resource buffers 
TCHAR g_szTitle[STR_LEN];                    // Main window caption 
TCHAR g_szResult[STR_LEN];                   // "Result" 
TCHAR g_szError[STR_LEN];                    // "Error" 
 
/* 
 * WinMain 
 * 
 * Purpose: 
 *  Main entry point of application. Should register the app class 
 *  if a previous instance has not done so and do any other one-time 
 *  initializations. 
 * 
 */ 
int APIENTRY WinMain (HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpCmdLine, int nCmdShow) 
{ 
   MSG msg; 
        
#ifdef WIN16 
   //  It is recommended that all 16 bit OLE applications set 
   //  their message queue size to 96. This improves the capacity 
   //  and performance of OLE's LRPC mechanism. 
   int cMsg = 96;                  // Recommend msg queue size for OLE 
   while (cMsg && !SetMessageQueue(cMsg))  // take largest size we can get. 
       cMsg -= 8; 
   if (!cMsg) 
       return -1;  // ERROR: we got no message queue        
#endif 
    
   // Load string constants 
   LoadString(hinst, IDS_PROGNAME, g_szTitle, STR_LEN); 
   LoadString(hinst, IDS_RESULT, g_szResult, STR_LEN); 
   LoadString(hinst, IDS_ERROR, g_szError, STR_LEN); 
    
   if (!hinstPrev) 
      if (!InitApplication(hinst)) 
         return (FALSE); 
 
   if(OleInitialize(NULL) != NOERROR) 
      return FALSE; 
       
   if (!InitInstance(hinst, nCmdShow)) 
      return (FALSE); 
 
   while (GetMessage(&msg, NULL, NULL, NULL)) 
   { 
      TranslateMessage(&msg); 
      DispatchMessage(&msg); 
   } 
    
   OleUninitialize(); 
    
   return (msg.wParam); // Returns the value from PostQuitMessage 
} 
 
/* 
 * InitApplication 
 * 
 * Purpose: 
 *  Registers window class 
 * 
 * Parameters: 
 *  hinst       hInstance of application 
 * 
 * Return Value: 
 *  TRUE if initialization succeeded, FALSE otherwise. 
 */ 
BOOL InitApplication (HINSTANCE hinst) 
{ 
   WNDCLASS wc; 
 
   wc.style = CS_DBLCLKS; 
   wc.lpfnWndProc = MainWndProc; 
   wc.cbClsExtra = 0; 
   wc.cbWndExtra = 0; 
   wc.hInstance = hinst; 
   wc.hIcon = LoadIcon(hinst, TEXT("ControlIcon")); 
   wc.hCursor = LoadCursor(NULL, IDC_ARROW); 
   wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 
   wc.lpszMenuName = TEXT("ControlMenu"); 
   wc.lpszClassName = TEXT("MainWndClass"); 
      
   return RegisterClass(&wc); 
 } 
 
/* 
 * InitInstance 
 * 
 * Purpose: 
 *  Creates and shows main window 
 * 
 * Parameters: 
 *  hinst           hInstance of application 
 *  nCmdShow        specifies how window is to be shown 
 * 
 * Return Value: 
 *  TRUE if initialization succeeded, FALSE otherwise. 
 */ 
BOOL InitInstance (HINSTANCE hinst, int nCmdShow) 
{ 
   
   g_hinst = hinst; 
   // Create Main Window 
   g_hwnd = CreateWindow(TEXT("MainWndClass"), g_szTitle, 
                       WS_OVERLAPPEDWINDOW, 
                       CW_USEDEFAULT, CW_USEDEFAULT, 
                       400, 200, 
                       NULL, NULL, hinst, NULL); 
   if (!g_hwnd) 
      return FALSE; 
    
   ShowWindow(g_hwnd, nCmdShow);                   
   UpdateWindow(g_hwnd);             
   return TRUE; 
} 
 
/* 
 * MainWndProc 
 * 
 * Purpose: 
 *  Window procedure for main window 
 * 
 */ 
LRESULT CALLBACK MainWndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
   static IHello FAR* phello = NULL;     
   HRESULT hr; 
   LPUNKNOWN punk; 
    
   switch (msg) 
   { 
      case WM_COMMAND: 
         switch (wParam) 
         { 
            case IDM_CREATEHELLO:    
                // Create Hello object and QueryInterface for IHello interface. 
                hr = CoCreateInstance(CLSID_Hello, NULL, CLSCTX_SERVER,  
                     IID_IUnknown, (void FAR* FAR*)&punk); 
                if (FAILED(hr))   
                { 
                    MessageBox(NULL, TEXT("CoCreateInstance"), g_szError, MB_OK);  
                    return 0L; 
                }                      
                hr = punk->QueryInterface(IID_IHello,  (void FAR* FAR*)&phello);    
                if (FAILED(hr))   
                { 
                    MessageBox(NULL, TEXT("QueryInterface(IID_IHello)"), g_szError, MB_OK); 
                    punk->Release();  
                    return 0L; 
                } 
                punk->Release(); 
                return 0L; 
                                
            case IDM_SETVISIBLE:   
                // Set Visible property to TRUE 
                hr = phello->put_Visible(TRUE); 
                if (FAILED(hr)) 
                    DisplayError(phello); 
                return 0L; 
                 
            case IDM_SETINVISIBLE:     
                // Set visible property to FALSE 
                hr = phello->put_Visible(FALSE); 
                if (FAILED(hr)) 
                    DisplayError(phello); 
                return 0L; 
                 
            case IDM_GETHELLOMESSAGE:     
            {    
                // Access Hello Message property and display it 
                // in a MessageBox 
                BSTR bstr = NULL;   // BSTR must be intialized before passing 
                                    // to get_HelloMessage. 
                hr = phello->get_HelloMessage(&bstr); 
                if (FAILED(hr)) 
                    DisplayError(phello); 
                else MessageBox(NULL, FROM_OLE_STRING(bstr), g_szResult, MB_OK);  
                 
                // Caller is responsible for freeing parameters and return values. 
                if (bstr) 
                    SysFreeString(bstr); 
                return 0L;    
            } 
               
            case IDM_SAYHELLO:     
                // Invoke SayHello method 
                hr = phello->SayHello(); 
                if (FAILED(hr)) 
                    DisplayError(phello); 
                return 0L; 
                 
            case IDM_RELEASEHELLO: 
                // Release the Hello object 
                phello->Release(); 
                phello = NULL; 
                return 0L; 
         } 
         break; 
          
      case WM_INITMENUPOPUP: 
      { 
         HMENU hmenu = (HMENU)wParam; 
          
         if (LOWORD(lParam) != 0) 
            return 0L; 
             
         // Enable or gray the appropriate menu items. phello indicates if an automation object 
         //  is currently being controlled.    
         EnableMenuItem(hmenu, IDM_CREATEHELLO,  MF_BYCOMMAND | (phello?MF_GRAYED:MF_ENABLED)); 
         EnableMenuItem(hmenu, IDM_SETVISIBLE,   MF_BYCOMMAND | (phello?MF_ENABLED:MF_GRAYED));  
         EnableMenuItem(hmenu, IDM_SETINVISIBLE,   MF_BYCOMMAND | (phello?MF_ENABLED:MF_GRAYED)); 
         EnableMenuItem(hmenu, IDM_GETHELLOMESSAGE,   MF_BYCOMMAND | (phello?MF_ENABLED:MF_GRAYED)); 
         EnableMenuItem(hmenu, IDM_SAYHELLO,  MF_BYCOMMAND | (phello?MF_ENABLED:MF_GRAYED)); 
         EnableMenuItem(hmenu, IDM_RELEASEHELLO, MF_BYCOMMAND | (phello?MF_ENABLED:MF_GRAYED)); 
         return 0L; 
      } 
       
      case WM_DESTROY: 
         if (phello) 
            phello->Release();                 
         PostQuitMessage(0); 
         break; 
 
      default:                          
         return DefWindowProc(hwnd, msg, wParam, lParam); 
   } 
    
   return NULL; 
} 
 
/* 
 * DisplayError 
 * 
 * Purpose: 
 *  Obtains Rich Error Information about the automation error from 
 *  the IErrorInfo interface. 
 * 
 */ 
void DisplayError(IHello FAR* phello) 
{   
   IErrorInfo FAR* perrinfo;     
   BSTR bstrDesc; 
   HRESULT hr; 
   ISupportErrorInfo FAR* psupporterrinfo;   
 
   hr = phello->QueryInterface(IID_ISupportErrorInfo, (LPVOID FAR*)&psupporterrinfo); 
   if (FAILED(hr))  
   { 
      MessageBox(NULL, TEXT("QueryInterface(IID_ISupportErrorInfo)"), g_szError, MB_OK); 
      return; 
   } 
    
   hr = psupporterrinfo->InterfaceSupportsErrorInfo(IID_IHello);    
   if (hr != NOERROR) 
   {    
       psupporterrinfo->Release(); 
       return; 
   } 
   psupporterrinfo->Release(); 
   
   // In this example only the error description is obtained and displayed.  
   // See the IErrorInfo interface for other information that is available.  
   hr = GetErrorInfo(0, &perrinfo);  
   if (FAILED(hr)) 
       return;    
   hr = perrinfo->GetDescription(&bstrDesc); 
   if (FAILED(hr))  
   { 
       perrinfo->Release();  
       return; 
   }   
    
   MessageBox(NULL, FROM_OLE_STRING(bstrDesc), g_szError, MB_OK);    
   SysFreeString(bstrDesc); 
} 
 
/* 
 * Quick & Dirty ANSI/Unicode conversion routines. These routines use a static 
 * buffer of fixed size to hold the converted string. Consequently these 
 * routines are limited to strings of size STRCONVERT_MAXLEN. Also the same 
 * buffer is reused when the routine is called a second time. So make sure 
 * that the converted string is used before the conversion routine is called 
 * again 
 */ 
#ifdef WIN32 
 
#ifndef UNICODE 
char* ConvertToAnsi(OLECHAR FAR* szW) 
{ 
  static char achA[STRCONVERT_MAXLEN];  
   
  WideCharToMultiByte(CP_ACP, 0, szW, -1, achA, STRCONVERT_MAXLEN, NULL, NULL);   
  return achA;  
}  
 
OLECHAR* ConvertToUnicode(char FAR* szA) 
{ 
  static OLECHAR achW[STRCONVERT_MAXLEN];  
 
  MultiByteToWideChar(CP_ACP, 0, szA, -1, achW, STRCONVERT_MAXLEN);   
  return achW;  
} 
#endif 
 
#endif