Sample 3: Using IPersistMoniker::Load to Load a Document

//****************************************
// MSXML OM test code
//
// adapted for multithreaded urlmon testing
//****************************************

#include <windows.h>
#include <windowsx.h>
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <urlmon.h>
#include <hlink.h>
#include <dispex.h>
#include "mshtml.h"
#include "msxml.h"

int MyStrToOleStrN(LPOLESTR pwsz, int cchWideChar, LPCTSTR psz);
#define ASSERT(x)  if(!(x)) DebugBreak()
#define CHECK_ERROR(cond, err) if (!(cond)) {pszErr=(err); goto done;}
#define SAFERELEASE(p) if (p) {(p)->Release(); p = NULL;} else ;
//
// SAFECAST(obj, type)
//
// This macro is extremely useful for enforcing strong typechecking on other
// macros.  It generates no code.
//
// Simply insert this macro at the beginning of an expression list for
// each parameter that must be typechecked.  For example, for the
// definition of MYMAX(x, y), where x and y absolutely must be integers,
// use:
//
//   #define MYMAX(x, y)    (SAFECAST(x, int), SAFECAST(y, int), ((x) > (y) ? (x) : (y)))
//
//
#define SAFECAST(_obj, _type) (((_type)(_obj)==(_obj)?0:0), (_type)(_obj))

#define WALK_ELEMENT_COLLECTION(pCollection, pDispItem) \
    {\
        long length;\
        \
        if (SUCCEEDED(pCollection->get_length(&length)) && length > 0)\
        {\
            VARIANT vIndex, vEmpty;\
            vIndex.vt = VT_I4;\
            vEmpty.vt = VT_EMPTY;\
                                 \
            for (long i=0; i<length; i++)\
            {\
                vIndex.lVal = i;\
                IDispatch *pDispItem = NULL;\
                if (SUCCEEDED(pCollection->item(vIndex, vEmpty, &pDispItem)))\
                {

#define END_WALK_ELEMENT_COLLECTION(pDispItem) \
                    pDispItem->Release();\
                }\
            }\
        }\
    }

//==========================================================================

class CTestBindStatusCallback : public IBindStatusCallback
                              , public IAuthenticate
                              , public IHttpSecurity

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

        // *** IAuthenticate ***
        STDMETHOD(Authenticate)(
            HWND *phwnd,
            LPWSTR *pszUsername,
            LPWSTR *pszPassword);

        // *** IBindStatusCallback ***
        STDMETHOD(OnStartBinding)(
            /* [in] */ DWORD grfBSCOption,
            /* [in] */ IBinding *pib);

        STDMETHOD(GetPriority)(
            /* [out] */ LONG *pnPriority);

        STDMETHOD(OnLowResource)(
            /* [in] */ DWORD reserved);

        STDMETHOD(OnProgress)(
            /* [in] */ ULONG ulProgress,
            /* [in] */ ULONG ulProgressMax,
            /* [in] */ ULONG ulStatusCode,
            /* [in] */ LPCWSTR szStatusText);

        STDMETHOD(OnStopBinding)(
            /* [in] */ HRESULT hresult,
            /* [in] */ LPCWSTR szError);

        STDMETHOD(GetBindInfo)(
            /* [out] */ DWORD *grfBINDF,
            /* [unique][out][in] */ BINDINFO *pbindinfo);

        STDMETHOD(OnDataAvailable)(
            /* [in] */ DWORD grfBSCF,
            /* [in] */ DWORD dwSize,
            /* [in] */ FORMATETC *pformatetc,
            /* [in] */ STGMEDIUM *pstgmed);

        STDMETHOD(OnObjectAvailable)(
            /* [in] */ REFIID riid,
            /* [iid_is][in] */ IUnknown *punk);

        /* *** IHttpSecurity ***  */
        STDMETHOD(GetWindow)(REFGUID rguidReason, HWND* phwnd);

        STDMETHOD(OnSecurityProblem)(DWORD dwProblem);

        // Worker routines

        IBinding*       m_pib;
        IMoniker*        m_pmk;
        IBindCtx*       m_pbc;
        HANDLE          m_hEvent;

        ULONG m_cRef;

        VOID Abort(); // Aborts the binding 
        ~CTestBindStatusCallback();
        CTestBindStatusCallback(IBindCtx *pbc, IMoniker *pmkIn, HANDLE hEvent);
    };

void Indent(int indent, FILE *fileID)
{
    while (indent-->0)
    {
        fprintf(fileID, "    ");
    }
}

//
// Dump an element attribute member if present.
//
void DumpAttrib(IXMLElement *pElem, BSTR bstrAttribName, FILE *fileID)
{
    VARIANT vProp;
    
    VariantInit(&vProp);

    if (SUCCEEDED(pElem->getAttribute(bstrAttribName, &vProp)))
    {
        if (vProp.vt == VT_BSTR)
        {
            fprintf(fileID, "%S=\"%S\" ", bstrAttribName, vProp.bstrVal);
        }
        VariantClear(&vProp);
    }
}

HRESULT DumpElement(IXMLElement *pElem, int indent, FILE *fileID)
{
    BSTR bstr = NULL;
    IXMLElementCollection * pChildren;

    Indent(indent, fileID);

    //
    // Dump the name of the NODE.
    //
    pElem->get_tagName(&bstr);
    fprintf(fileID, "<%S ", bstr?bstr:L"XML");

    //
    // Dump the attributes if present.
    //
    DumpAttrib(pElem, L"VALUE", fileID);
    DumpAttrib(pElem, L"HREF", fileID);
    DumpAttrib(pElem, L"HOUR", fileID);
    DumpAttrib(pElem, L"DAY", fileID);
    DumpAttrib(pElem, L"IsClonable", fileID);
    DumpAttrib(pElem, L"Type", fileID);

    //
    // Find the children if they exist.
    //
    if (SUCCEEDED(pElem->get_children(&pChildren)) && pChildren)
    {
        fprintf(fileID, ">\n");

        WALK_ELEMENT_COLLECTION(pChildren, pDisp)
        {
            //
            // pDisp will iterate over an IDispatch for each item in the collection.
            //
            IXMLElement * pChild;
            if (SUCCEEDED(pDisp->QueryInterface(IID_IXMLElement, (void **)&pChild)))
            {
                DumpElement(pChild, indent+1, fileID);
                pChild->Release();
            }
        }
        END_WALK_ELEMENT_COLLECTION(pDisp);
        pChildren->Release();
        //
        // Have output children display closing tag.
        //
        Indent(indent, fileID);
        fprintf(fileID, "</%S>\n", bstr?bstr:L"XML"); 
    }
    else
    {
        //
        // No children so terminate tag on same line.
        //
        fprintf(fileID, "/>\n");
    }

    if (bstr)
        SysFreeString(bstr);

    return S_OK;
}

HANDLE g_hMutex = NULL;
ULONG g_ulNextThreadId = 0;

DWORD WINAPI LoadFunc(CHAR *pszUrl)
{

FILE *fileID = stdout;
    HRESULT hr;
    IXMLElement *pElem = NULL;
    IUnknown *pUnk = NULL;
    IXMLDocument *pDoc = NULL;
    IMoniker *pmk = NULL;
    HANDLE hEvent = NULL;
    IBindStatusCallback *pPreviousCallback = NULL;
    IPersistMoniker *pPersistmk = NULL;
    PSTR pszErr = NULL;
    IBindCtx *pbc = NULL;
    IBindStatusCallback *pbsc = NULL;
    DWORD dwRet;
    LONG len;
    WCHAR *pwszUrl;

    ASSERT(SUCCEEDED(hr));
    len = lstrlenA(pszUrl);
    
    pwszUrl = (WCHAR *)LocalAlloc(LMEM_FIXED, (len + 1)*sizeof(WCHAR));
    ASSERT(pwszUrl);
    MyStrToOleStrN(pwszUrl, len + 1, pszUrl);

    //
    // Dump the root element and all children of the XML object.
    //

    ASSERT(SUCCEEDED(hr));
    if (!pDoc)
    {
        hr = CoCreateInstance(CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER,
                                IID_IUnknown, (void**)&pUnk);
    }

    CHECK_ERROR (pUnk, "CoCreateInstance");

    hr = pUnk->QueryInterface(IID_IXMLDocument, (void **)&pDoc);

    ASSERT(SUCCEEDED(hr));
    pUnk->Release();
    pUnk = NULL;
    CHECK_ERROR (pDoc, "QI for IXMLDocument");

    hr = pDoc->QueryInterface(IID_IPersistMoniker, (void **)&pPersistmk);
    ASSERT(SUCCEEDED(hr));

    CHECK_ERROR(pPersistmk, "QI for IPersistMoniker");

    hr = CreateURLMoniker(NULL, pwszUrl, &pmk);
    ASSERT(SUCCEEDED(hr));
    CHECK_ERROR(pmk, "CreateURLMoniker");

    hr = CreateBindCtx(0, &pbc);
    if((!pbc) || FAILED(hr))
        goto done;

    pbc->AddRef();

    hEvent = CreateEventA(0, 0, 0, 0);
    pbsc = new CTestBindStatusCallback(pbc, pmk, hEvent);
    ASSERT(pbsc);
    if(!pbsc)
    {
        fprintf (stderr, "Out of memory ");
        goto done;
    }
    pbsc->AddRef();

    hr = RegisterBindStatusCallback(pbc, pbsc, &pPreviousCallback, 0);
    if(FAILED(hr))
    {
        fprintf (stderr, "RegisterBindStatusCallback : Failed");
        goto done;
    }
    
    hr = pPersistmk->Load(FALSE, pmk, pbc, 0);

    ASSERT(SUCCEEDED(hr));

    if(pPersistmk)
    {
        pPersistmk->Release();
        pPersistmk = NULL;
    }

    while(1)
    {
        MSG msg;
        dwRet =  MsgWaitForMultipleObjects(1, &hEvent, FALSE, INFINITE, QS_ALLINPUT);
        if(dwRet == WAIT_OBJECT_0)
        {
            // We're done
            break;
         }
         else
         {
            GetMessage(&msg, NULL, 0, 0);
            DispatchMessage(&msg);
         }
    }
    // Ready to start dumping the document.

    //
    // Now walk the OM and look at interesting things.
    //
    hr = pDoc->get_root(&pElem);
    CHECK_ERROR(pElem, "Thread Failed to get_root of XML object");

    DumpElement(pElem, 0, fileID);
    
done: // Clean up.
    fclose(fileID);
    pElem->Release();
    pDoc->Release();
    LocalFree(pwszUrl);
    pbsc->Release();
    return 0;    
}

int MyStrToOleStrN(LPOLESTR pwsz, int cchWideChar, LPCTSTR psz)
{
    int i;
    i=MultiByteToWideChar(CP_ACP, 0, psz, -1, pwsz, cchWideChar);
    if (!i)
    {
        //DBG_WARN("MyStrToOleStrN string too long; truncated");
        pwsz[cchWideChar-1]=0;
    }
    else
        ZeroMemory(pwsz+i, sizeof(OLECHAR)*(cchWideChar-i));

    return i;
}

#define NUM_THREADS 1
const WCHAR *szUrls[NUM_THREADS] = {  L"http://ie_tools/bharats/msnbc0.cdf",
                                      //L"http://ie_tools/bharats/msnbc1.cdf",
                                     // L"http://ie_tools/bharats/msnbc2.cdf",
                                      //L"http://ie_tools/bharats/msnbc3.cdf",
                                      //L"http://ie_tools/bharats/msnbc4.cdf"
                                    };

int _cdecl main (int argc, char **argv)
{
    PSTR pszErr = NULL;
    IStream                *pStm = NULL;
    IPersistStreamInit     *pPSI = NULL;
    IXMLElement            *pElem = NULL;
    char                  buf[MAX_PATH];
    char                  *pszURL;
    UINT uNumThreads = NUM_THREADS; // Atleast three threads
    UINT ui;// iterator
    DWORD dwThreadId;
    HANDLE hThd;
    WCHAR *pwszStrUrlCopy = NULL;
    LONG len;

    HRESULT hr;

    //
    // Check usage.
    //
    if (argc < 2)
    {
        fprintf (stderr, "Usage:   %s URL\n",argv[0]);
        fprintf (stderr, "Eg %s c:\\nt\\private\\inet\\xml\\test\\channel.uni\n", argv[0]);
        fprintf (stderr, "or %s http://ohserv/users/julianj/channel.xml\n", argv[0]);
        exit (1);
    }
    
   
    // HACK if passed in a file name, expand if it doesn't look like a URL.
    //
    
    if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, argv[1], 7, "http://", 7) == CSTR_EQUAL)
    {
        pszURL = argv[1];
    }
    else
    {
        pszURL = buf;
        GetFullPathName(argv[1], MAX_PATH, pszURL, NULL);
    }

    hr = CoInitialize(NULL);
    ASSERT(SUCCEEDED(hr));

    //
    // Create an empty XML document.
    //
    LoadFunc(pszURL);

    len = lstrlen(pszURL) + 1;
    

    //
    // Dump the root element and all children of the XML object onto screen.

done: // Clean up.
    //
    // Release any used interfaces.
    //
    SAFERELEASE(pPSI);
    SAFERELEASE(pStm);
    SAFERELEASE(pElem);

    if (pszErr)
        fprintf (stderr, "%s, last error %d\n", pszErr, GetLastError());

    return 0;
}

STDMETHODIMP CTestBindStatusCallback::QueryInterface(
                                REFIID riid, 
                                LPVOID * ppvObj)
{
    if (IsEqualIID(riid, IID_IBindStatusCallback) || 
        IsEqualIID(riid, IID_IUnknown))
    {
        *ppvObj = SAFECAST(this, IBindStatusCallback*);
    }
    else if (IsEqualIID(riid, IID_IAuthenticate))
    {
        *ppvObj = SAFECAST(this, IAuthenticate*);
    }
    else if (IsEqualIID(riid, IID_IHttpSecurity))
    {
        *ppvObj = SAFECAST(this, IHttpSecurity*);
    }
    else
    {
        *ppvObj = NULL;
        return E_NOINTERFACE;
    }

    ((LPUNKNOWN)*ppvObj)->AddRef();
    return NOERROR;
}

ULONG CTestBindStatusCallback::AddRef(void)
{
    return ++m_cRef;
}

ULONG CTestBindStatusCallback::Release(void)
{
    if( 0L != --m_cRef )
        return m_cRef;

    delete this;
    return 0L;
}

VOID CTestBindStatusCallback::Abort()
{
    if(m_pib)
    {
        m_pib->Abort();
    }
}

CTestBindStatusCallback::CTestBindStatusCallback(IBindCtx *pbc, IMoniker *pmkIn, HANDLE hEvent)
{

    
    // Initialize object.
    m_cRef=0L;

    m_pib = NULL;
    m_pbc = pbc;
    if(m_pbc)
        m_pbc->AddRef();

    m_pmk = pmkIn;
    if(m_pmk)
        m_pmk->AddRef();

    m_hEvent = hEvent;
}

CTestBindStatusCallback::~CTestBindStatusCallback()
{    
    SAFERELEASE(m_pib);
    SAFERELEASE(m_pbc);

    SAFERELEASE(m_pmk);
    if(m_hEvent)
        CloseHandle(m_hEvent);
}

// IAuthenticate Methods
STDMETHODIMP CTestBindStatusCallback::Authenticate(
    HWND *phwnd,
    LPWSTR *pszUsername,
    LPWSTR *pszPassword)
{
    return E_NOTIMPL;
}

// IBindStatusCallback Methods
STDMETHODIMP CTestBindStatusCallback::OnStartBinding(DWORD grfBSCOption, 
IBinding *pibIn)
{

    return S_OK;

}

STDMETHODIMP CTestBindStatusCallback::GetPriority(LONG *pnPriority)
{
    return S_OK;
}

STDMETHODIMP CTestBindStatusCallback::OnLowResource(DWORD reserved)
{
    return S_OK; //BUGBUG
}

STDMETHODIMP CTestBindStatusCallback::OnProgress(
    ULONG ulProgress,
    ULONG ulProgressMax,
    ULONG ulStatusCode,
    LPCWSTR szStatusText)
{
    return S_OK;
}

STDMETHODIMP CTestBindStatusCallback::OnStopBinding(
    HRESULT hresult,
    LPCWSTR szError)
{
    HRESULT hr = S_OK;
    if(SUCCEEDED(hresult))
    {
        OutputDebugString(TEXT("Done Loading succesfully"));    
    }
    // Signal event to wake up thread to navigate children.
    SetEvent(m_hEvent);

    SAFERELEASE(m_pib);
    return hr;
}

STDMETHODIMP CTestBindStatusCallback::GetBindInfo(
    DWORD *grfBINDF, /* [out] */
    BINDINFO *pbindinfo /* [unique][out][in] */ )
{
    return E_NOTIMPL;

}

STDMETHODIMP CTestBindStatusCallback::OnDataAvailable(
    /* [in] */ DWORD grfBSCF,
    /* [in] */ DWORD dwSize,
    /* [in] */ FORMATETC *pformatetc,
    /* [in] */ STGMEDIUM *pstgmed)
{
    return S_OK;
}

STDMETHODIMP CTestBindStatusCallback::OnObjectAvailable(
    /* [in] */ REFIID riid,
    /* [iid_is][in] */ IUnknown *punk)
{
    return S_OK;
}

/* *** IHttpSecurity ***  */
        // BUGBUG - Do we need to implement this interface
STDMETHODIMP CTestBindStatusCallback::GetWindow(REFGUID rguidReason, HWND* 
phwnd)
{
    if (!phwnd)
        return E_POINTER;

    *phwnd = NULL; // BUGBUG
    return S_OK;
}

STDMETHODIMP CTestBindStatusCallback::OnSecurityProblem(DWORD dwProblem)
{
    // Force UI - return S_FALSE for all problems.
    return S_FALSE;
}



© 1999 Microsoft Corporation. All rights reserved. Terms of use.