//+-------------------------------------------------------------------
//
//  File:       oleimpl.cxx
//
//  Contents:   This file contins the DLL entry points
//                      LibMain
//                      DllGetClassObject (Bindings key func)
//			CAdvBndCF (class factory)
//			CAdvBnd   (actual class implementation)
//
//  Classes:	CAdvBndCF, CAdvBnd
//
//
//  History:	30-Nov-92      SarahJ      Created
//              31-Dec-93      ErikGav     Chicago port
//---------------------------------------------------------------------

// Turn off ole Cairol IUnknown
#include    "headers.cxx"
#pragma hdrstop
#include    <stdio.h>
#include    <stdarg.h>
#include    "wterm.h"


#define IDM_DEBUG 0x100

static const TCHAR *szAppName = TEXT("Test OLE Server");
static const char *szFatalError = "OLESRV - Fatal Error";

void MsgBox(char *pszMsg)
{
    MessageBoxA(NULL, pszMsg, szFatalError, MB_OK);
}

void HrMsgBox(char *pszMsg, HRESULT hr)
{
    char awcBuf[512];

    // Build string for output
    wsprintfA(awcBuf, "%s HRESULT = %lx", pszMsg, hr);

    // Display message box
    MessageBoxA(NULL, &awcBuf[0], szFatalError, MB_OK);
}

//+-------------------------------------------------------------------
//  Class:    CTestServerApp
//
//  Synopsis: Class that holds application-wide data and methods
//
//  Methods:  InitApp
//            CloseApp
//            GetEmbeddedFlag
//
//  History:  17-Dec-92     DeanE   Created
//--------------------------------------------------------------------
class FAR CTestServerApp
{
public:

// Constructor/Destructor
    CTestServerApp();
    ~CTestServerApp();

    SCODE InitApp         (LPSTR lpszCmdline);
    SCODE CloseApp        (void);
    BOOL  GetEmbeddedFlag (void);
    ULONG IncEmbeddedCount(void);
    ULONG DecEmbeddedCount(void);

private:
    IClassFactory *_pteClassFactory;
    ULONG          _cEmbeddedObjs;  // Count of embedded objects this server
                                    // is controlling now
    DWORD          _dwRegId;        // OLE registration ID
    BOOL           _fRegistered;    // TRUE if srv was registered w/OLE
    BOOL           _fEmbedded;      // TRUE if OLE started us at the request
                                    //   of an embedded obj in a container app
};

CTestServerApp tsaMain;
HWND g_hMain;

void ProcessCmdLine(LPSTR, BOOL *);

//+--------------------------------------------------------------
//  Function:   CTestServerApp::CTestServerApp
//
//  Synopsis:   Constructor - initialize members
//
//  Parameters: None
//
//  Returns:    None
//
//  History:    17-Dec-92   DeanE   Created
//---------------------------------------------------------------
CTestServerApp::CTestServerApp()
{
    _pteClassFactory = NULL;
    _dwRegId         = 0;
    _fRegistered     = FALSE;
    _fEmbedded	     = TRUE;
    _cEmbeddedObjs   = 0;
}


//+--------------------------------------------------------------
//  Function:   CTestServerApp::~CTestServerApp
//
//  Synopsis:   Insure pointers are free - note this is mainly for
//              error-checking.
//
//  Parameters: None
//
//  Returns:    None
//
//  History:    17-Dec-92   DeanE   Created
//---------------------------------------------------------------
CTestServerApp::~CTestServerApp()
{
    Win4Assert(_pteClassFactory == NULL &&
               "Class factory should have been released");
}


//+--------------------------------------------------------------
//  Function:   CTestServerApp::InitApp
//
//  Synopsis:   Initialize this instance of the app.
//
//  Parameters: [lpszCmdline] - Command line of the application.
//
//  Returns:    S_OK if everything was initialized, or an error if not.
//
//  History:    17-Dec-92   DeanE   Created
//
//  Notes:      If this does not return, the CloseApp method should
//              still be called for proper cleanup.
//---------------------------------------------------------------
SCODE CTestServerApp::InitApp(LPSTR lpszCmdline)
{
    SCODE sc;

    // Check OLE version running
    // BUGBUG - NYI by OLE
    //   Bail out if we are not running with an acceptable version of OLE

    // Process Command Line arguments
    ProcessCmdLine(lpszCmdline, &_fEmbedded);

    // Create the applications class factory - note that we have to free
    //   at a later time
    _pteClassFactory = new CAdvBndCF();

    if (NULL == _pteClassFactory)
    {
        MsgBox("Class Object Creation Failed");
        return(E_ABORT);
    }

    // Register the class with OLE
    sc = CoRegisterClassObject(
           CLSID_AdvBnd,
           _pteClassFactory,
           CLSCTX_LOCAL_SERVER,
	   REGCLS_MULTIPLEUSE,
           &_dwRegId);

    if (S_OK == sc)
    {
        _fRegistered = TRUE;
    }
    else
    {
        HrMsgBox("CoRegisterClassObject FAILED", sc);
    }

    return(sc);
}


//+--------------------------------------------------------------
//  Function:   CTestServerApp::CloseApp
//
//  Synopsis:   Clean up resources this instance of the app is using.
//
//  Parameters: None
//
//  Returns:    S_OK if everything was cleaned up, or an error if not.
//
//  History:    17-Dec-92   DeanE   Created
//---------------------------------------------------------------
SCODE CTestServerApp::CloseApp()
{
    // Revoke the class object, if registered
    if (TRUE == _fRegistered)
    {
        CoRevokeClassObject(_dwRegId);
    }

    // Release this apps class factory, and insure the returned count is 0
    if (NULL != _pteClassFactory)
    {

      // NB: Workaround for ref count problem.

      #define HACK 1
      #if HACK
        _pteClassFactory->Release();
        _pteClassFactory = NULL;
      #else
        if (0 == _pteClassFactory->Release())
        {
            _pteClassFactory = NULL;
        }
        else
        {
            Win4Assert("Release on class factory returned positive ref count");
            // BUGBUG - Log error
        }
      #endif
    }

    return(S_OK);
}


//+--------------------------------------------------------------
//  Function:   CTestServerApp::GetEmbeddedFlag
//
//  Synopsis:   Returns TRUE if app was started for an embedded object,
//              FALSE if standalone.
//
//  Parameters: None
//
//  Returns:    BOOL (_fEmbedded)
//
//  History:    17-Dec-92   DeanE   Created
//
//  Notes:      BUGBUG - This should be an inline method
//---------------------------------------------------------------
CTestServerApp::GetEmbeddedFlag()
{
    return(_fEmbedded);
}


//+--------------------------------------------------------------
//  Function:   CTestServerApp::IncEmbeddedCount
//
//  Synopsis:   Increments the count of embedded objects the server
//              has open.
//
//  Parameters: None
//
//  Returns:    ULONG (_cEmbeddedObjs)
//
//  History:    17-Dec-92   DeanE   Created
//
//  Notes:      BUGBUG - This should be an inline method
//---------------------------------------------------------------
ULONG CTestServerApp::IncEmbeddedCount()
{
    return(++_cEmbeddedObjs);
}


//+--------------------------------------------------------------
//  Function:   CTestServerApp::DecEmbeddedCount
//
//  Synopsis:   Decrements the count of embedded objects the server
//              has open.  If 0 are left and we were running for an
//              embedded object(s), shut down.
//
//  Parameters: None
//
//  Returns:    ULONG (_cEmbeddedObjs)
//
//  History:    17-Dec-92   DeanE   Created
//
//  Notes:      BUGBUG - This should be an inline method
//---------------------------------------------------------------
ULONG CTestServerApp::DecEmbeddedCount()
{
    if ((0 == --_cEmbeddedObjs) && _fEmbedded)
    {
        // We are done so revoke our OLE stuff. We need to do this as
        // soon as we know that we are shutting down so that the window
        // for returning a bad class object is shut.
        CloseApp();

        // Tell window to die
	SendMessage(g_hMain, WM_USER, 0xFFFFFFFF, 0xFFFFFFFF);
    }

    return(_cEmbeddedObjs);
}


//+--------------------------------------------------------------
// Function:    ProcessCmdline
//
// Synopsis:    Checks the cmd line parameters, in particular for
//              '/Embedding' or '-Embedding'.
//
// Parameters:  [lpszCmdLine] - Command line buffer.
//              [pfEmbedded]  - Flag should be set to true if we get
//                              the '/Embedding' switch.
//
// Returns:     void
//
// History:	25-Nov-92   DeanE   Created
//
// Notes:	Only two valid commandlines for this program:
//		(1) -Embedding when started by OLE or (2) Null
//		string if started from the command line.
//---------------------------------------------------------------
void ProcessCmdLine(LPSTR lpszCmdline, BOOL *pfEmbedded)
{
    if (lpszCmdline[0] == 0)
    {
	*pfEmbedded = FALSE;
	return;
    }

    if (strcmp(lpszCmdline, "-Embedding") == 0)
    {
	*pfEmbedded = TRUE;
	return;
    }

    MsgBox("Received an invalid command line!");
    *pfEmbedded = FALSE;

    return;
}

void Display(TCHAR *pszFmt, ...)
{
    va_list marker;
    TCHAR szBuffer[256];

    va_start(marker, pszFmt);

    #ifdef UNICODE
    int iLen = vswprintf(szBuffer, pszFmt, marker);
    #else
    int iLen = vsprintf(szBuffer, pszFmt, marker);
    #endif

    va_end(marker);

    // Display the message on terminal window
    SendMessage(g_hMain, WM_PRINT_LINE, iLen, (LONG) szBuffer);
}




//+-------------------------------------------------------------------------
//
//  Function:	ProcessMenu
//
//  Synopsis:	Gets called when a WM_COMMAND message received.
//
//  Arguments:	[hWindow] - handle for the window
//		[uiMessage] - message id
//		[wParam] - word parameter
//		[lParam] - long parameter
//
//  Returns:	DefWindowProc result
//
//  History:	06-Aug-92 Ricksa    Created
//
//--------------------------------------------------------------------------
long ProcessMenu(HWND hWindow, UINT uiMessage, WPARAM wParam, LPARAM lParam,
    void *)
{
    if ((uiMessage == WM_SYSCOMMAND) && (wParam == IDM_DEBUG))
    {
	// Request for a debug breakpoint!
	DebugBreak();
    }


    return (DefWindowProc(hWindow, uiMessage, wParam, lParam));
}


//+-------------------------------------------------------------------------
//
//  Function:	ProcessChar
//
//  Synopsis:	Gets called when a WM_CHAR message received.
//
//  Arguments:	[hWindow] - handle for the window
//		[uiMessage] - message id
//		[wParam] - word parameter
//		[lParam] - long parameter
//
//  Returns:	DefWindowProc result
//
//  History:	06-Aug-92 Ricksa    Created
//
//--------------------------------------------------------------------------
long ProcessChar(HWND hWindow, UINT uiMessage, WPARAM wParam, LPARAM lParam,
    void *)
{
    return (DefWindowProc(hWindow, uiMessage, wParam, lParam));
}


//+-------------------------------------------------------------------------
//
//  Function:	ProcessClose
//
//  Synopsis:	Gets called when a NC_DESTROY message received.
//
//  Arguments:	[hWindow] - handle for the window
//		[uiMessage] - message id
//		[wParam] - word parameter
//		[lParam] - long parameter
//
//  Returns:	DefWindowProc result
//
//  History:	06-Aug-92 Ricksa    Created
//
//--------------------------------------------------------------------------
long ProcessClose(
    HWND hWindow,
    UINT uiMessage,
    WPARAM wParam,
    LPARAM lParam,
    void *pvCallBackData)
{
    // Take default action with message
    return (DefWindowProc(hWindow, uiMessage, wParam, lParam));
}

//+-------------------------------------------------------------------
//
//  Function:	WinMain
//
//  Synopsis:   Entry point to DLL - does little else
//
//  Arguments:
//
//  Returns:    TRUE
//
//  History:    21-Nov-92  SarahJ  Created
//
//--------------------------------------------------------------------
int WINAPI WinMain(
    HINSTANCE hInstance,
    HINSTANCE hPrevInstance,
    char *lpszCmdLine,
    int nCmdShow)
{
    // For windows message
    MSG msg;
    BOOL bRet;
    HRESULT hr;

    // Register the window class
    bRet = TermRegisterClass(hInstance, NULL, (LPTSTR) szAppName,
	                     (LPTSTR) MAKEINTRESOURCE(IDI_APPLICATION));

    if (!bRet)
    {
        MsgBox("TermRegisterClass FAILED");
        return 1;
    }

    // Create the server window
    bRet = TermCreateWindow(
	(LPTSTR) szAppName,
	(LPTSTR) szAppName,
	NULL,
	ProcessMenu,
	ProcessChar,
	ProcessClose,
	SW_SHOWMINIMIZED,
	&g_hMain,
	NULL);

    if (!bRet)
    {
        MsgBox("TermCreateWindow FAILED");
        return 1;
    }

    // Add debug option to system menu
    HMENU hmenu = GetSystemMenu(g_hMain, FALSE);

    AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hmenu, MF_STRING | MF_ENABLED, IDM_DEBUG, TEXT("Debug"));

    // Look up the thread mode from the win.ini file.
    DWORD thread_mode;
    TCHAR buffer[80];
    int len;

    len = GetProfileString( TEXT("OleSrv"),
                            TEXT("ThreadMode"),
                            TEXT("MultiThreaded"),
                            buffer,
                            sizeof(buffer) / sizeof(TCHAR));

    if (lstrcmp(buffer, TEXT("ApartmentThreaded")) == 0)
    {
	thread_mode = COINIT_APARTMENTTHREADED;
	hr = CoInitialize(NULL);
    }
    else
    {
#ifdef MULTI_THREADING
	thread_mode = COINIT_MULTITHREADED;
	hr = CoInitializeEx(NULL, thread_mode);
#else
	hr = E_INVALIDARG;
#endif
    }

    if (S_OK != hr)
    {
	HrMsgBox("CoInitialize FAILED", hr);
        return(1);
    }


    // Initialize Application
    if (S_OK != tsaMain.InitApp(lpszCmdLine))
    {
        tsaMain.CloseApp();
        return(1);
    }

    if (tsaMain.GetEmbeddedFlag())
    {
        // We're running as an embedded app
        // Don't show the main window unless we're instructed to do so
        // BUGBUG - In-place editing is NYI
	ShowWindow(g_hMain, SW_SHOWMINIMIZED);
    }
    else
    {
        // We are not running as an embedded app - show the main window
        ShowWindow(g_hMain, nCmdShow);
    }

    UpdateWindow(g_hMain);


    // message loop
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // If we get here, we initialized OLE so let's uninitialize it.
    CoUninitialize();

    return (msg.wParam);	   /* Returns the value from PostQuitMessage */
}



//+-------------------------------------------------------------------
//
//  Class:    CAdvBndCF
//
//  Synopsis: Class Factory for CAdvBnd
//
//  Interfaces:  IUnknown      - QueryInterface, AddRef, Release
//               IClassFactory - CreateInstance
//
//  History:  21-Nov-92  SarahJ  Created
//
//--------------------------------------------------------------------


//+-------------------------------------------------------------------
//
//  Member:	CAdvBndCF::CAdvBndCF()
//
//  Synopsis:	The constructor for CAdvBnd.
//
//  Arguments:  None
//
//  History:    21-Nov-92  SarahJ  Created
//
//--------------------------------------------------------------------

CAdvBndCF::CAdvBndCF() : _cRefs(1)
{
    // Load the class object for the class to aggregate.
    HRESULT hresult = CoGetClassObject(CLSID_BasicBnd, CLSCTX_SERVER, NULL,
	IID_IClassFactory, (void **) &_xifac);

    return;
}

//+-------------------------------------------------------------------
//
//  Member:	CAdvBnd::~CAdvBndObj()
//
//  Synopsis:	The destructor for CAdvBnd.
//
//  History:    21-Nov-92  SarahJ  Created
//
//--------------------------------------------------------------------

CAdvBndCF::~CAdvBndCF()
{
    return;
}


//+-------------------------------------------------------------------
//
//  Method:	CAdvBndCF::QueryInterface
//
//  Synopsis:   Only IUnknown and IClassFactory supported
//
//--------------------------------------------------------------------
STDMETHODIMP CAdvBndCF::QueryInterface(REFIID iid, void FAR * FAR * ppv)
{
    if (GuidEqual(iid, IID_IUnknown)
	|| GuidEqual(iid, IID_IClassFactory))
    {
	*ppv = (IUnknown *) this;
	AddRef();
	return S_OK;
    }
    else
    {
        *ppv = NULL;
	return E_NOINTERFACE;
    }
}

STDMETHODIMP_(ULONG) CAdvBndCF::AddRef(void)
{
    return(++_cRefs);
}

STDMETHODIMP_(ULONG) CAdvBndCF::Release(void)
{
    if (--_cRefs == 0)
    {
	delete this;
        return(0);
    }

    return _cRefs;
}





//+-------------------------------------------------------------------
//
//  Method:	CAdvBndCF::CreateInstance
//
//  Synopsis:   This is called by Binding process to create the
//              actual class object
//
//--------------------------------------------------------------------

STDMETHODIMP CAdvBndCF::CreateInstance(
    IUnknown FAR* pUnkOuter,
    REFIID iidInterface,
    void FAR* FAR* ppv)
{
    Display(TEXT("CAdvBndCF::CreateInstance called\n"));

    if (pUnkOuter != NULL)
    {
	return E_FAIL;
    }

    CAdvBnd * lpcBB = new FAR CAdvBnd((IClassFactory *) _xifac);

    if (lpcBB == NULL)
    {
	return E_OUTOFMEMORY;
    }

    HRESULT hresult = lpcBB->QueryInterface(iidInterface, ppv);

    lpcBB->Release();

    return hresult;
}

STDMETHODIMP CAdvBndCF::LockServer(BOOL fLock)
{
    return E_FAIL;
}


//+-------------------------------------------------------------------
//
//  Member:	CAdvBnd::CAdvBnd()
//
//  Synopsis:	The constructor for CAdvBnd. I
//
//  Arguments:  None
//
//  History:    21-Nov-92  SarahJ  Created
//
//--------------------------------------------------------------------

CAdvBnd::CAdvBnd(IClassFactory *pcfBase) : _xiunk(), _dwRegister(0), _cRefs(1)
{
    HRESULT hresult = pcfBase->CreateInstance((IUnknown *) this, IID_IUnknown,
	(void **) &_xiunk);

    tsaMain.IncEmbeddedCount();

    return;
}

//+-------------------------------------------------------------------
//
//  Member:	CAdvBnd::~CAdvBndObj()
//
//  Synopsis:	The destructor for CAdvBnd.
//
//  History:    21-Nov-92  SarahJ  Created
//
//--------------------------------------------------------------------

CAdvBnd::~CAdvBnd()
{
    Display(TEXT("CAdvBndCF::~CAdvBnd called\n"));

    if (_dwRegister != 0)
    {
	// Get the running object table
	IRunningObjectTable *prot;

	HRESULT hresult = GetRunningObjectTable(0, &prot);

        if (hresult != S_OK)
        {
            HrMsgBox("CAdvBnd::~CAdvBnd GetRunningObjectTable failed", hresult);
        }
        else
        {
	    hresult = prot->Revoke(_dwRegister);

            if (hresult != S_OK)
            {
                HrMsgBox("CAdvBnd::~CAdvBnd Revoke failed", hresult);
            }

	    prot->Release();
        }
    }

    tsaMain.DecEmbeddedCount();
    return;
}


//+-------------------------------------------------------------------
//
//  Member:	CAdvBnd::QueryInterface
//
//  Returns:    SUCCESS_SUCCCESS
//
//  History:    21-Nov-92  SarahJ  Created
//
//--------------------------------------------------------------------
STDMETHODIMP CAdvBnd::QueryInterface(REFIID iid, void ** ppunk)
{
    Display(TEXT("CAdvBnd::QueryInterface called\n"));

    if (GuidEqual(iid, IID_IUnknown))
    {
	*ppunk = (IUnknown *) this;
	AddRef();
	return S_OK;
    }
    else if ((GuidEqual(iid, IID_IPersistFile))
	|| (GuidEqual(iid, IID_IPersist)))
    {
	*ppunk = (IPersistFile *) this;
	AddRef();
	return S_OK;
    }

    return _xiunk->QueryInterface(iid, ppunk);
}

STDMETHODIMP_(ULONG) CAdvBnd::AddRef(void)
{
    return ++_cRefs;
}

STDMETHODIMP_(ULONG) CAdvBnd::Release(void)
{
    if (--_cRefs == 0)
    {
	delete this;
        return(0);
    }

    return _cRefs;
}

//+-------------------------------------------------------------------
//
//  Member:	CAdvBnd::Load
//
//  Synopsis:   IPeristFile interface - needed 'cause we bind with
//              file moniker and BindToObject insists on calling this
//
//  History:    21-Nov-92  SarahJ  Created
//
//--------------------------------------------------------------------
STDMETHODIMP CAdvBnd::Load(LPCWSTR lpszFileName, DWORD grfMode)
{
    Display(TEXT("CAdvBndCF::Load called\n"));

    // Forward call to delegated class
    IPersistFile *pipfile;

    HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile,
	(void **) &pipfile);

    hresult = pipfile->Load(lpszFileName, grfMode);

    pipfile->Release();

    if (FAILED(hresult))
    {
	// Make sure delegated too class liked what it got/
	// BUGBUG: Can't just forward hresults!
	return hresult;
    }

    // Create a file moniker
    IMoniker *pmk;
    hresult = CreateFileMoniker((LPWSTR)lpszFileName, &pmk);

    if (FAILED(hresult))
    {
        HrMsgBox("CAdvBnd::Load CreateFileMoniker failed", hresult);
        return hresult;
    }

    // Get the running object table
    IRunningObjectTable *prot;

    hresult = GetRunningObjectTable(0, &prot);

    if (FAILED(hresult))
    {
        HrMsgBox("CAdvBnd::Load GetRunningObjectTable failed", hresult);
        return hresult;
    }

    // Register in the running object table
    IUnknown *punk;
    QueryInterface(IID_IUnknown, (void **) &punk);

    hresult = prot->Register(0, punk, pmk, &_dwRegister);

    if (FAILED(hresult))
    {
        HrMsgBox("CAdvBnd::Load Register failed", hresult);
        return hresult;
    }

    // Set filetime to known value
    FILETIME filetime;
    memset(&filetime, 'B', sizeof(filetime));

    // Set time to some known value
    prot->NoteChangeTime(_dwRegister, &filetime);

    // Release uneeded objects
    pmk->Release();
    prot->Release();
    punk->Release();

    return S_OK;
}

//+-------------------------------------------------------------------
//
//  Member:	CAdvBnd::Save
//
//  Synopsis:   IPeristFile interface - save
//              does little but here for commentry
//
//  History:    21-Nov-92  SarahJ  Created
//
//--------------------------------------------------------------------
STDMETHODIMP CAdvBnd::Save(LPCWSTR lpszFileName, BOOL fRemember)
{
    Display(TEXT("CAdvBndCF::Save called\n"));

    // Forward call to delegated class
    IPersistFile *pipfile;

    HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile,
	(void **) &pipfile);

    hresult = pipfile->Save(lpszFileName, fRemember);

    pipfile->Release();

    return hresult;
}


//+-------------------------------------------------------------------
//
//  Member:	CAdvBnd::SaveCpmpleted
//		CAdvBnd::GetCurFile
//		CAdvBnd::IsDirty
//
//  Synopsis:   More IPeristFile interface methods
//
//  History:    21-Nov-92  SarahJ  Created
//
//--------------------------------------------------------------------
STDMETHODIMP CAdvBnd::SaveCompleted(LPCWSTR lpszFileName)
{
    Display(TEXT("CAdvBndCF::SaveCompleted called\n"));

    // Forward call to delegated class
    IPersistFile *pipfile;

    HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile,
	(void **) &pipfile);

    hresult = pipfile->SaveCompleted(lpszFileName);

    pipfile->Release();

    return hresult;
}

STDMETHODIMP CAdvBnd::GetCurFile(LPWSTR FAR *lpszFileName)
{
    Display(TEXT("CAdvBndCF::GetCurFile called\n"));

    // Forward call to delegated class
    IPersistFile *pipfile;

    HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile,
	(void **) &pipfile);

    hresult = pipfile->GetCurFile(lpszFileName);

    pipfile->Release();

    return hresult;
}

STDMETHODIMP CAdvBnd::IsDirty()
{
    Display(TEXT("CAdvBndCF::IsDirty called\n"));

    // Forward call to delegated class
    IPersistFile *pipfile;

    HRESULT hresult = _xiunk->QueryInterface(IID_IPersistFile,
	(void **) &pipfile);

    hresult = pipfile->IsDirty();

    pipfile->Release();

    return hresult;
}

//+-------------------------------------------------------------------
//
//  Interface:  IPersist
//
//  Synopsis:   IPersist interface methods
//              Need to return a valid class id here
//
//  History:    21-Nov-92  SarahJ  Created
//

STDMETHODIMP CAdvBnd::GetClassID(LPCLSID classid)
{
    Display(TEXT("CAdvBndCF::GetClassID called\n"));

    *classid = CLSID_AdvBnd;
    return S_OK;
}