#ifdef WIN32

#ifdef UNICODE
    #define FROM_OLE_STRING(str) str
    #define TO_OLE_STRING(str) str 
#else
    #define FROM_OLE_STRING(str) ConvertToAnsi(str)
    char* ConvertToAnsi(OLECHAR FAR* szW);  
    #define TO_OLE_STRING(str) ConvertToUnicode(str)
    OLECHAR* ConvertToUnicode(char FAR* szA);   
    // Maximum length of string that can be converted between Ansi & Unicode
    #define STRCONVERT_MAXLEN 300         
#endif

#else  // WIN16
  #define APIENTRY far pascal  
  #define TCHAR char
  #define TEXT(sz) sz 
  #define FROM_OLE_STRING(str) str  
  #define TO_OLE_STRING(str) str  
  #define LPTSTR LPSTR
  
  // Windows NT defines the following in windowsx.h
  #define GET_WM_COMMAND_ID(w,l) (w)
  #define GET_WM_COMMAND_CMD(w,l) HIWORD(l)
  #define GET_WM_COMMAND_HWND(w,l) LOWORD(l)
#endif

#include "tlb.h"
 
#define STRICT

// Menu IDs
#define IDM_DRAWLINE  101
#define IDM_CLEAR     102
#define IDM_EXIT      103  

// Dialog ID
#define IDD_DRAWLINE  101
// Icon ID
#define IDI_ICON      102

// Dialog Control IDs
#define IDC_THICKNESS     101
#define IDC_CHOOSECOLOR   102
#define IDC_STARTPOINT_X  103
#define IDC_STARTPOINT_Y  104
#define IDC_ENDPOINT_X    105
#define IDC_ENDPOINT_Y    106 
#define IDC_STATIC         -1

// MAX len of string table entries
#define STR_LEN   200

// String table constants
#define IDS_Name                   1 
#define IDS_ErrorLoadingTypeLib    2
#define IDS_ProgID                 3 
#define IDS_Unexpected             1001
#define IDS_OutOfMemory            1002   
#define IDS_InvalidIndex           1003
#define IDS_CollectionFull         1004
#define IDS_LineFromOtherInstance  1005
#define IDS_CantAddEndPoints       1006  
#define IDS_PointFromOtherInstance 1007 
#define IDS_NoVisibleXCoordinate   1008
#define IDS_NoVisibleYCoordinate   1009  
#define IDS_NoStartPoint           1010
#define IDS_NoEndPoint             1011   

// SCODEs for the Lines Application. This is required for vtable-binding
// Automation objects want to return custom HRESULTs. All the OLE-defined 
// FACILITY_ITF codes have a code value which lies in the region 0x0000-0x01FFF.
// While it is legal for the definer to use any code, it is highly recommended
// that only code values in the range 0x0200-0xFFFF be used, as this will reduce the
// possiblity of accidental confusion with any OLE-defined errors.
#define LINES_E_FIRST MAKE_SCODE(SEVERITY_ERROR, FACILITY_ITF, 0x0200)  

#define LINES_E_UNEXPECTED              (LINES_E_FIRST + 0x0) 
// Unexpected error
#define LINES_E_OUTOFMEMORY             (LINES_E_FIRST + 0x1) 
// Out of memory
#define LINES_E_INVALIDINDEX            (LINES_E_FIRST + 0x2) 
// Invalid index to Points or Lines collections 
#define LINES_E_COLLECTIONFULL          (LINES_E_FIRST + 0x3) 
// Points or Lines collection is full
#define LINES_E_LINEFROMOTHERINSTANCE   (LINES_E_FIRST + 0x4)
// Line from another instance of this application cannot be added.
#define LINES_E_CANTADDENDPOINTS        (LINES_E_FIRST + 0x5)   
// End points of line cannot be added to collection. (Make sure line has two end points).
#define LINES_E_POINTFROMOTHERINSTANCE  (LINES_E_FIRST + 0x6)
// Point from another instance of this application cannot be added.
#define LINES_E_NOVISIBLEXCOORDINATE    (LINES_E_FIRST + 0x7)
// No visible X coordinate.
#define LINES_E_NOVISIBLEYCOORDINATE    (LINES_E_FIRST + 0x8)
// No visible Y coordinate.
#define LINES_E_NOSTARTPOINT            (LINES_E_FIRST + 0x9)
// Line does not have a start point.
#define LINES_E_NOENDPOINT              (LINES_E_FIRST + 0xA)
// Line does not have an end point.

// Number of SCODEs
#define SCODE_COUNT 11   

// Function prototypes
int APIENTRY WinMain (HINSTANCE, HINSTANCE, LPSTR, int);
BOOL InitApplication (HINSTANCE);
BOOL InitInstance (HINSTANCE);
BOOL ProcessCmdLine(LPSTR pCmdLine, LPDWORD pdwRegisterCF, LPDWORD pdwRegisterActiveObject, int nCmdShow);
void Uninitialize(DWORD dwRegisterCF, DWORD dwRegisterActiveObject);
HRESULT LoadTypeInfo(ITypeInfo FAR* FAR* pptinfo, REFCLSID clsid);
HRESULT RaiseException(int nID, REFGUID rguid);

#ifdef WIN16
extern "C" LRESULT __export CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM); 
extern "C" BOOL __export CALLBACK DrawLineDialogFunc(HWND, UINT, WPARAM, LPARAM);                  
#else 
extern "C" LRESULT CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM); 
extern "C" BOOL CALLBACK DrawLineDialogFunc(HWND, UINT, WPARAM, LPARAM); 
#endif   
 
// Class definitions
class CPane;  
class CLine;
class CPoint;
class CLines;
class CPoints;  

// ISupportErrorInfo interface implementation
interface CSupportErrorInfo : public ISupportErrorInfo 
{
public:
    // IUnknown methods 
    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
    STDMETHOD_(ULONG, AddRef)(void);
    STDMETHOD_(ULONG, Release)(void); 
    
    // ISupportErrorInfo method
    STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);  
     
    CSupportErrorInfo(IUnknown FAR* punkObject, REFIID riid); 
private:
    LPUNKNOWN m_punkObject;  // IUnknown of Object that implements this interface 
    GUID m_iid;
};     

class FAR CApplicationCF : public IClassFactory
{
public:
    // IUnknown methods 
    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
    STDMETHOD_(ULONG, AddRef)(void);
    STDMETHOD_(ULONG, Release)(void); 
    
    // IClassFactory methods
    STDMETHOD(CreateInstance)(IUnknown FAR* punkOuter, REFIID riid, 
                              void FAR* FAR* ppv);
    STDMETHOD(LockServer)(BOOL fLock);    
    
    CApplicationCF();
    
private:
    ULONG m_cRef;                   // Reference count
}; 

    
class FAR CApplication : public IApplication
{
public:
    /* IUnknown methods */
    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
    STDMETHOD_(ULONG, AddRef)();
    STDMETHOD_(ULONG, Release)();

    /* IDispatch methods */
    STDMETHOD(GetTypeInfoCount)(UINT FAR* pctinfo);
    STDMETHOD(GetTypeInfo)(       
      UINT itinfo,
      LCID lcid,
      ITypeInfo FAR* FAR* pptinfo);
    STDMETHOD(GetIDsOfNames)(       
      REFIID riid,
      OLECHAR FAR* FAR* rgszNames,
      UINT cNames,
      LCID lcid,
      DISPID FAR* rgdispid);
    STDMETHOD(Invoke)(       
      DISPID dispidMember,
      REFIID riid,
      LCID lcid,
      WORD wFlags,
      DISPPARAMS FAR* pdispparams,
      VARIANT FAR* pvarResult,
      EXCEPINFO FAR* pexcepinfo,
      UINT FAR* puArgErr);

    /* IApplication automation exposed properties and methods */   
    STDMETHOD(get_Application)(IApplication FAR* FAR* ppApplication);
    STDMETHOD(get_FullName)(BSTR FAR* pbstr);
    STDMETHOD(get_Name)(BSTR FAR* pbstr);
    STDMETHOD(get_Parent)(IApplication FAR* FAR* ppApplication);
    STDMETHOD(put_Visible)(VARIANT_BOOL bVisible);
    STDMETHOD(get_Visible)(VARIANT_BOOL FAR* pbVisible);
    STDMETHOD(Quit)();
    STDMETHOD(get_Pane)(IPane FAR* FAR* ppPane);
    STDMETHOD(CreateLine)(ILine FAR* FAR* ppLine);
    STDMETHOD(CreatePoint)(IPoint FAR* FAR* ppPoint);
    
    /* CApplication methods */
    STDMETHOD_(void, Draw)();
    STDMETHOD_(void, OnSize)(unsigned int nWidth, unsigned int nHeight);
    STDMETHOD_(void, ShowWindow)(int nCmdShow); 
    STDMETHOD_(void, CreateAndDrawLine)();
    STDMETHOD_(void, ClearPane)();  
    
    static HRESULT Create(HWND hwnd, CApplication FAR* FAR* ppApplication); // Creates and intializes Applicaton object 
    CApplication();
    ~CApplication();    
    
public:
    HWND m_hwnd;                   // Application window.     
    HINSTANCE m_hinst;             // Hinstance of application. 
    BSTR m_bstrName;               // Name of application.
    BSTR m_bstrProgID;             // ProgID of application. 
    BOOL m_bUserClosing;           // User is closing the application.
    
private:
    LPTYPEINFO m_ptinfo;           // Type information of IApplication interface.
    BSTR m_bstrFullName;           // Full name of application.
    BOOL m_bVisible;               // Is window visible?
    CPane FAR* m_pPane;            // Pointer to the Pane object.   
    ULONG m_cRef;                  // Reference count.   
    CSupportErrorInfo m_SupportErrorInfo; // ISupportErrorInfo interface implementation 
};

class FAR CPane : public IPane
{
public:
    /* IUnknown methods */
    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
    STDMETHOD_(ULONG, AddRef)();
    STDMETHOD_(ULONG, Release)();

    /* IDispatch methods */
    STDMETHOD(GetTypeInfoCount)(UINT FAR* pctinfo);
    STDMETHOD(GetTypeInfo)(       
      UINT itinfo,
      LCID lcid,
      ITypeInfo FAR* FAR* pptinfo);
    STDMETHOD(GetIDsOfNames)(       
      REFIID riid,
      OLECHAR FAR* FAR* rgszNames,
      UINT cNames,
      LCID lcid,
      DISPID FAR* rgdispid);
    STDMETHOD(Invoke)(       
      DISPID dispidMember,
      REFIID riid,
      LCID lcid,
      WORD wFlags,
      DISPPARAMS FAR* pdispparams,
      VARIANT FAR* pvarResult,
      EXCEPINFO FAR* pexcepinfo,
      UINT FAR* puArgErr);

    /* IPane automation exposed properties & methods */    
    STDMETHOD(get_Lines)(ILines FAR* FAR* ppLines);
    STDMETHOD(get_Points)(IPoints FAR* FAR* ppPoints);
    STDMETHOD(get_MaxX)(int FAR* pnMaxX);
    STDMETHOD(get_MaxY)(int FAR* pnMaxY);
    STDMETHOD(Clear)();
    STDMETHOD(Refresh)();
    
    /* CPane methods */
    STDMETHOD_(void, Draw)(); 
    STDMETHOD_(void, OnSize)(unsigned int nWidth, unsigned int nHeight);    
    STDMETHOD_(HDC,  GetDC)();  
    STDMETHOD_(void, ReleaseDC)(HDC hdc);   
    STDMETHOD_(void, InvalidateRect)(LPRECT prc);
    STDMETHOD_(void, Update)(void);
    STDMETHOD_(BOOL, AddPoint)(CPoint FAR* pPoint);
    STDMETHOD_(void, RemovePoint)(CPoint FAR* pPoint);
    
    static HRESULT Create(HWND hwnd, CPane FAR* FAR* ppPane); // Creates and intializes Pane object 
    CPane();
    ~CPane();
    
private:
    LPTYPEINFO m_ptinfo;           // Type information of IPane interface.
    HWND m_hwnd;                   // Main window.
    CLines FAR *m_pLines;          // Lines collection.
    CPoints FAR* m_pPoints;        // Points collection.
    int m_nMaxX;                   // Maximum visible X coordinate in twips.
    int m_nMaxY;                   // Maximum visible Y coordinate in twips.
    int m_nWidth;                  // Width of pane in twips.
    int m_nHeight;                 // Height of pane in twips.  
    ULONG m_cRef;                  // Reference count.   
    CSupportErrorInfo m_SupportErrorInfo; // ISupportErrorInfo interface implementation 
};

class FAR CLine : public ILine
{
public:
    /* IUnknown methods */
    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
    STDMETHOD_(ULONG, AddRef)();
    STDMETHOD_(ULONG, Release)();

    /* IDispatch methods */
    STDMETHOD(GetTypeInfoCount)(UINT FAR* pctinfo);
    STDMETHOD(GetTypeInfo)(       
      UINT itinfo,
      LCID lcid,
      ITypeInfo FAR* FAR* pptinfo);
    STDMETHOD(GetIDsOfNames)(       
      REFIID riid,
      OLECHAR FAR* FAR* rgszNames,
      UINT cNames,
      LCID lcid,
      DISPID FAR* rgdispid);
    STDMETHOD(Invoke)(       
      DISPID dispidMember,
      REFIID riid,
      LCID lcid,
      WORD wFlags,
      DISPPARAMS FAR* pdispparams,
      VARIANT FAR* pvarResult,
      EXCEPINFO FAR* pexcepinfo,
      UINT FAR* puArgErr);

    /* ILine automation exposed properties & methods */   
    STDMETHOD(get_Color)(long FAR* plColorref);
    STDMETHOD(put_Color)(long lColorref);
    STDMETHOD(get_EndPoint)(IPoint FAR* FAR* ppPoint);
    STDMETHOD(putref_EndPoint)(IPoint FAR* pPoint);
    STDMETHOD(get_StartPoint)(IPoint FAR* FAR* ppPoint);
    STDMETHOD(putref_StartPoint)(IPoint FAR* pPoint);
    STDMETHOD(get_Thickness)(int FAR* pnThickness);
    STDMETHOD(put_Thickness)(int nThickness);
    
    /* CLine methods */
    STDMETHOD_(void, Draw)(HDC hdc);     
    STDMETHOD_(void, GetInvalidateRect)(LPRECT prc);
    STDMETHOD_(BOOL, AddEndPointsToPane)(CPane FAR* pPane);
    STDMETHOD_(void, RemoveEndPointsFromPane)(CPane FAR* pPane);  
    
    static HRESULT Create(CLine FAR* FAR* ppLine); // Creates and intializes Line object 
    CLine();
    ~CLine();
    
private:
    LPTYPEINFO m_ptinfo;           // Type information of ILine interface.
    COLORREF m_colorref;           // RGB color of line.
    CPoint FAR* m_pPointStart;     // Start point of line.
    CPoint FAR* m_pPointEnd;       // End point of line.
    int m_nThickness;              // Line thickness in twips. 
    ULONG m_cRef;                  // Reference count.
    CSupportErrorInfo m_SupportErrorInfo; // ISupportErrorInfo interface implementation 
};

class FAR CPoint : public IPoint
{
public:
    /* IUnknown methods */
    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
    STDMETHOD_(ULONG, AddRef)();
    STDMETHOD_(ULONG, Release)();

    /* IDispatch methods */
    STDMETHOD(GetTypeInfoCount)(UINT FAR* pctinfo);
    STDMETHOD(GetTypeInfo)(       
      UINT itinfo,
      LCID lcid,
      ITypeInfo FAR* FAR* pptinfo);
    STDMETHOD(GetIDsOfNames)(       
      REFIID riid,
      OLECHAR FAR* FAR* rgszNames,
      UINT cNames,
      LCID lcid,
      DISPID FAR* rgdispid);
    STDMETHOD(Invoke)(       
      DISPID dispidMember,
      REFIID riid,
      LCID lcid,
      WORD wFlags,
      DISPPARAMS FAR* pdispparams,
      VARIANT FAR* pvarResult,
      EXCEPINFO FAR* pexcepinfo,
      UINT FAR* puArgErr);

    /* IPoint automation exposed properties & methods */    
    STDMETHOD(get_x)(int FAR* pnX);
    STDMETHOD(put_x)(int nX);
    STDMETHOD(get_y)(int FAR* pnY);
    STDMETHOD(put_y)(int nY);
    
    /* CPoint methods */
    STDMETHOD_(ULONG, InternalAddRef)();
    STDMETHOD_(ULONG, InternalRelease)();
    STDMETHOD_(int, get_x)();      
    STDMETHOD_(int, get_y)(); 
    
    static HRESULT Create(CPoint FAR* FAR* ppPoint); // Creates and intializes Point object 
    CPoint();
    ~CPoint();
    
private:
    LPTYPEINFO m_ptinfo;           // Type information of IPoint interface.
    int m_nX;                      // X coordinate of point in twips.
    int m_nY;                      // Y coordinate of point in twips.
    ULONG m_cInternalRef;          // Reference count for the use of the Points collection only.
    ULONG m_cRef;                  // Reference count.  
    CSupportErrorInfo m_SupportErrorInfo; // ISupportErrorInfo interface implementation 
};

class FAR CLines : public ILines
{
public:
    /* IUnknown methods */
    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
    STDMETHOD_(ULONG, AddRef)();
    STDMETHOD_(ULONG, Release)();

    /* IDispatch methods */
    STDMETHOD(GetTypeInfoCount)(UINT FAR* pctinfo);
    STDMETHOD(GetTypeInfo)(       
      UINT itinfo,
      LCID lcid,
      ITypeInfo FAR* FAR* pptinfo);
    STDMETHOD(GetIDsOfNames)(       
      REFIID riid,
      OLECHAR FAR* FAR* rgszNames,
      UINT cNames,
      LCID lcid,
      DISPID FAR* rgdispid);
    STDMETHOD(Invoke)(       
      DISPID dispidMember,
      REFIID riid,
      LCID lcid,
      WORD wFlags,
      DISPPARAMS FAR* pdispparams,
      VARIANT FAR* pvarResult,
      EXCEPINFO FAR* pexcepinfo,
      UINT FAR* puArgErr);

    /* ILines automation exposed properties & methods */ 
    STDMETHOD(Add)(ILine FAR* pLine);
    STDMETHOD(get_Count)(long FAR* lCount);
    STDMETHOD(get_Item)(long lIndex, ILine FAR* FAR* ppLine);
    STDMETHOD(get__NewEnum)(IUnknown FAR* FAR* ppunkEnum);
    STDMETHOD(Remove)(long lIndex);
    
    /* CLines methods */
    STDMETHOD_(void, Draw)(HDC hdc);
    STDMETHOD_(void, Clear)();   
    
    static HRESULT Create(ULONG lMaxSize, long lLBound, CPane FAR* pPane, CLines FAR* FAR* ppLines); // Creates and intializes Lines object 
    CLines();
    ~CLines();
    
private:
    LPTYPEINFO m_ptinfo;           // Type information of ILines interface.
    SAFEARRAY FAR *m_psa;          // Safe array that holds Lines collection items.
    ULONG m_cElements;             // Number of items in Lines collection.
    ULONG m_cMax;                  // Maximum number of items Lines collection can hold.
    long m_lLBound;                // Lower bound of index of Lines collection.
    CPane FAR* m_pPane;            // Pointer to the Pane object that contains this Lines collection.  
    ULONG m_cRef;                  // Reference count.     
    CSupportErrorInfo m_SupportErrorInfo; // ISupportErrorInfo interface implementation 
};

class FAR CPoints : public IPoints
{
public:
    /* IUnknown methods */
    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
    STDMETHOD_(ULONG, AddRef)();
    STDMETHOD_(ULONG, Release)();

    /* IDispatch methods */
    STDMETHOD(GetTypeInfoCount)(UINT FAR* pctinfo);
    STDMETHOD(GetTypeInfo)(       
      UINT itinfo,
      LCID lcid,
      ITypeInfo FAR* FAR* pptinfo);
    STDMETHOD(GetIDsOfNames)(       
      REFIID riid,
      OLECHAR FAR* FAR* rgszNames,
      UINT cNames,
      LCID lcid,
      DISPID FAR* rgdispid);
    STDMETHOD(Invoke)(       
      DISPID dispidMember,
      REFIID riid,
      LCID lcid,
      WORD wFlags,
      DISPPARAMS FAR* pdispparams,
      VARIANT FAR* pvarResult,
      EXCEPINFO FAR* pexcepinfo,
      UINT FAR* puArgErr);

    /* IPoints automation exposed properties & methods */    
    STDMETHOD(get_Count)(long FAR* plCount);
    STDMETHOD(get_Item)(long lIndex, IPoint FAR* FAR* ppPoint);
    STDMETHOD(get__NewEnum)(IUnknown FAR* FAR* ppunkEnum);
    
    /* CPoints methods */
    STDMETHOD_(BOOL, Add)(CPoint FAR* pPointNew);
    STDMETHOD_(BOOL, Remove)(CPoint FAR* pPointRemove);
    STDMETHOD_(void, Clear)();   
    STDMETHOD_(void, GetMaxXMaxY)(int FAR* pnX, int FAR* pnY, LPRECT prc);  
    
    static HRESULT Create(ULONG lMaxSize, long lLBound, CPane FAR* pPane, CPoints FAR* FAR* ppPoints); // Creates and intializes Points object 
    CPoints();
    ~CPoints();
    
private:
    LPTYPEINFO m_ptinfo;           // Type information of IPoints interface.
    SAFEARRAY FAR *m_psa;          // Safe array that holds Points collection items.
    ULONG m_cElements;             // Number of items in Points collection.
    ULONG m_cMax;                  // Maximum number of items Points collection can hold.
    long m_lLBound;                // Lower bound of index of Points collection.     
    CPane FAR* m_pPane;            // Pointer to the Pane object that contains this Points collection.  
    ULONG m_cRef;                  // Reference count.
    CSupportErrorInfo m_SupportErrorInfo; // ISupportErrorInfo interface implementation 
};

class FAR CEnumVariant : public IEnumVARIANT
{
public:
    // IUnknown methods 
    STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj);
    STDMETHOD_(ULONG, AddRef)();
    STDMETHOD_(ULONG, Release)();

    // IEnumVARIANT methods 
    STDMETHOD(Next)(ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched);
    STDMETHOD(Skip)(ULONG cElements);
    STDMETHOD(Reset)();
    STDMETHOD(Clone)(IEnumVARIANT FAR* FAR* ppenum);
    
    static HRESULT Create(SAFEARRAY FAR*, ULONG, CEnumVariant FAR* FAR*); // Creates and intializes Enumerator
    CEnumVariant();
    ~CEnumVariant();
    
private:
    ULONG m_cRef;           // Reference count                                 
    ULONG m_cElements;      // Number of elements in enumerator. 
    long m_lLBound;         // Lower bound of index.
    long m_lCurrent;        // Current index.
    SAFEARRAY FAR* m_psa;   // Safe array that holds elements.
}; 
 
// Structure filled by dialog from user input to create a line.
typedef struct _lineinfo
{
    COLORREF colorref;    // RGB color of line.
    POINT ptStart;        // Start point of line.   
    POINT ptEnd;          // End point of line.
    int nThickness;       // Thickness of line.
} LINEINFO, FAR* LPLINEINFO;
 
extern CApplication FAR* g_pApplication;
