Windows2003-3790/inetcore/mshtml/iextag/combobox.cxx
2020-09-30 16:53:55 +02:00

634 lines
15 KiB
C++

#include "headers.h"
#pragma MARK_DATA(__FILE__)
#pragma MARK_CODE(__FILE__)
#pragma MARK_CONST(__FILE__)
#include "iextag.h"
#include "utils.hxx"
#include "combobox.hxx"
/////////////////////////////////////////////////////////////////////////////
//
// CCombobox
//
/////////////////////////////////////////////////////////////////////////////
const CBaseCtl::PROPDESC CCombobox::s_propdesc[] =
{
{_T("value"), VT_BSTR},
NULL
};
enum
{
VALUE = 0
};
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//+------------------------------------------------------------------------
//
// Members: CCombobox::CCombobox
// CCombobox::~CCombobox
//
// Synopsis: Constructor/destructor
//
//-------------------------------------------------------------------------
CCombobox::CCombobox()
{
}
CCombobox::~CCombobox()
{
int i;
if (m_pSink)
delete m_pSink;
if (_pSinkBody)
{
delete _pSinkBody;
}
for (i = 0; i < 2; i++)
{
if (_apSinkElem[i])
{
delete _apSinkElem[i];
}
}
}
HRESULT
CCombobox::Detach()
{
if (_pPrimaryMarkup)
{
_pPrimaryMarkup->Release();
}
if (m_pHTMLPopup)
m_pHTMLPopup->Release();
return S_OK;
}
HRESULT
CCombobox::Init()
{
HRESULT hr = S_OK;
BSTR bstrEvent = NULL;
VARIANT_BOOL vSuccess = VARIANT_FALSE;
CContextAccess a(_pSite);
hr = a.Open(CA_ELEM | CA_ELEM2);
if (hr)
goto Cleanup;
// this puppy is ref counted when used.
m_pSink = new CEventSink (this);
if (!m_pSink)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
//
// we want to sink a few events.
//
bstrEvent = SysAllocString (L"onclick");
if (!bstrEvent)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
a.Elem2()->attachEvent (bstrEvent, (IDispatch *) m_pSink, &vSuccess);
if (vSuccess == VARIANT_TRUE)
{
hr = S_OK;
}
else
{
hr = E_FAIL;
}
Cleanup:
if (bstrEvent)
{
SysFreeString(bstrEvent);
}
return hr;
}
HRESULT
CCombobox::put_value(BSTR v)
{
return GetProps()[VALUE].Set(v);
}
HRESULT
CCombobox::get_value(BSTR * pv)
{
return GetProps()[VALUE].Get(pv);
}
//+------------------------------------------------------------------------
//
// Member: CCombobox::ProcOnClick
//
// Synopsis: Handles the onclick events.
//
//-------------------------------------------------------------------------
HRESULT STDMETHODCALLTYPE
CCombobox::ProcOnClick (CEventSink *pSink)
{
HRESULT hr = S_OK;
long lElemLeft, lElemTop, lElemWidth, lElemHeight;
IHTMLDocument *pDoc = NULL;
IMarkupServices *pMarkupSrv = NULL;
IMarkupPointer *pMarkupPStart = NULL;
IMarkupPointer *pMarkupPEnd = NULL;
IHTMLElement *pHtml = NULL;
IHTMLElement *pBody = NULL;
IHTMLElement *pElem = NULL;
IHTMLElement2 *pElem2 = NULL;
BSTR bstrEvent = NULL;
VARIANT_BOOL vSuccess = VARIANT_FALSE;
IDispatch *pDocMain = NULL;
IOleWindow *pIOleWnd = NULL;
HWND hwndMain;
RECT rcClient;
CContextAccess a(_pSite);
hr = a.Open(CA_ELEM);
if (hr)
goto Cleanup;
// VARIANT var;
// var.vt == VT_EMPTY;
if (pSink != m_pSink)
{
Assert(m_pHTMLPopup);
if (pSink == _apSinkElem[0])
{
a.Elem()->put_innerText(_T("test1"));
}
else
{
a.Elem()->put_innerText(_T("test2"));
}
m_pHTMLPopup->hide();
return hr;
}
// ISSUE: hr?
a.Elem()->get_offsetLeft(&lElemLeft);
a.Elem()->get_offsetTop(&lElemTop);
a.Elem()->get_offsetWidth(&lElemWidth);
a.Elem()->get_offsetHeight(&lElemHeight);
// get the current main doc window location
// ISSUE: hr?
a.Elem()->get_document(&pDocMain);
// get the oleWindow
hr = pDocMain->QueryInterface(IID_IOleWindow, (void **)&pIOleWnd);
if (FAILED(hr))
goto Cleanup;
pDocMain->Release();
// this window can be cached
hr = pIOleWnd->GetWindow(&hwndMain);
hr = S_OK;
GetWindowRect(hwndMain, &rcClient);
lElemTop = lElemTop + lElemHeight + rcClient.top;
lElemLeft = lElemLeft + rcClient.left;
pIOleWnd->Release();
if (m_pHTMLPopup)
{
//
// we have the popup
// just make sure it shows up
// show it modal
//
/*
hr = m_pHTMLPopup->show(a.Elem(),
lElemLeft, lElemTop,
lElemWidth, 100,
VARIANT_TRUE);
*/
return hr;
}
//
// create a popup window
// if there is no window yet
//
hr = CoCreateInstance(CLSID_HTMLPopup,
NULL,
CLSCTX_INPROC_SERVER,
IID_IHTMLPopup,
(void **) &m_pHTMLPopup);
if (FAILED(hr))
return hr;
//
// create elements in the popup doc
//
// hr = m_pHTMLPopup->getDoc(&pDoc);
hr = m_pHTMLPopup->get_document(&pDoc);
if (FAILED(hr))
goto Cleanup;
//
// get the markup services interface from the doc
// so that we can construct a markup tree
//
hr = pDoc->QueryInterface(IID_IMarkupServices, (void **)&pMarkupSrv);
if (FAILED(hr))
goto Cleanup;
hr = pDoc->QueryInterface(IID_IMarkupContainer, (void **)&_pPrimaryMarkup);
if (FAILED(hr))
goto Cleanup;
hr = pMarkupSrv->CreateMarkupPointer(&pMarkupPStart);
if (FAILED(hr))
goto Cleanup;
hr = pMarkupSrv->CreateMarkupPointer(&pMarkupPEnd);
if (FAILED(hr))
goto Cleanup;
hr = pMarkupPStart->MoveToContainer(_pPrimaryMarkup, TRUE);
if (FAILED(hr))
goto Cleanup;
hr = pMarkupPEnd->MoveToContainer(_pPrimaryMarkup, FALSE);
if (FAILED(hr))
goto Cleanup;
#define METHOD1 1
//
// ISSUE : METHOD 2 crashes in CHtmInfo::Init
//
#ifdef METHOD2
hr = pMarkupSrv->ParseString(_T("<HTML><BODY><INPUT></BODY></HTML>"),
0,
&_pPrimaryMarkup, pMarkupPStart, pMarkupPEnd);
if (FAILED(hr))
goto Cleanup;
ReleaseInterface(pMarkupSrv);
ReleaseInterface(pMarkupPStart);
ReleaseInterface(pMarkupPEnd);
#endif
//
// this is the prefered method of creating the content of the popup
//
#ifdef METHOD1
hr = pMarkupSrv->CreateElement(TAGID_HTML, 0, &pHtml);
if (FAILED(hr))
goto Cleanup;
hr = pMarkupSrv->InsertElement(pHtml, pMarkupPStart, pMarkupPEnd);
if (FAILED(hr))
goto Cleanup;
hr = pMarkupSrv->CreateElement(TAGID_BODY,
_T("style='border:solid 1;overflow:hidden'"),
&pBody);
if (FAILED(hr))
goto Cleanup;
pMarkupPStart->MoveAdjacentToElement(pHtml, ELEM_ADJ_AfterBegin);
if (FAILED(hr))
goto Cleanup;
pMarkupPEnd->MoveAdjacentToElement(pHtml, ELEM_ADJ_BeforeEnd);
if (FAILED(hr))
goto Cleanup;
hr = pMarkupSrv->InsertElement(pBody, pMarkupPStart, pMarkupPEnd);
if (FAILED(hr))
goto Cleanup;
hr = pMarkupSrv->CreateElement( TAGID_INPUT,
_T("type=checkbox value='text1' \
style='width:100%;border:0;background:white' \
"),
&pElem);
if (FAILED(hr))
goto Cleanup;
pMarkupPStart->MoveAdjacentToElement(pBody, ELEM_ADJ_AfterBegin);
if (FAILED(hr))
goto Cleanup;
pMarkupPEnd->MoveAdjacentToElement(pBody, ELEM_ADJ_BeforeEnd);
if (FAILED(hr))
goto Cleanup;
hr = pMarkupSrv->InsertElement(pElem, pMarkupPStart, pMarkupPEnd);
if (FAILED(hr))
goto Cleanup;
pMarkupPStart->MoveAdjacentToElement(pElem, ELEM_ADJ_AfterEnd);
if (FAILED(hr))
goto Cleanup;
bstrEvent = SysAllocString (L"onclick");
if (!bstrEvent)
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
hr = pElem->QueryInterface(IID_IHTMLElement2, (void **)&pElem2);
if (FAILED(hr))
goto Cleanup;
_apSinkElem[0] = new CEventSink (this);
if (!_apSinkElem[0])
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
pElem2->attachEvent (bstrEvent, (IDispatch *) _apSinkElem[0], &vSuccess);
if (vSuccess == VARIANT_TRUE)
{
hr = S_OK;
}
else
{
hr = E_FAIL;
goto Cleanup;
}
ReleaseInterface(pElem2);
pElem2 = NULL;
ReleaseInterface(pElem);
pElem = NULL;
hr = pMarkupSrv->CreateElement( TAGID_INPUT,
_T("type=button value='text2' \
style='width:100%;border:0;background:white' \
"),
&pElem);
if (FAILED(hr))
goto Cleanup;
pMarkupPEnd->MoveAdjacentToElement(pBody, ELEM_ADJ_BeforeEnd);
if (FAILED(hr))
goto Cleanup;
hr = pMarkupSrv->InsertElement(pElem, pMarkupPStart, pMarkupPEnd);
if (FAILED(hr))
goto Cleanup;
hr = pElem->QueryInterface(IID_IHTMLElement2, (void **)&pElem2);
if (FAILED(hr))
goto Cleanup;
_apSinkElem[1] = new CEventSink (this);
if (!_apSinkElem[1])
{
hr = E_OUTOFMEMORY;
goto Cleanup;
}
pElem2->attachEvent (bstrEvent, (IDispatch *) _apSinkElem[1], &vSuccess);
if (vSuccess == VARIANT_TRUE)
{
hr = S_OK;
}
else
{
hr = E_FAIL;
goto Cleanup;
}
#endif
//
// position the window just under the element
// not supported due to a pdlparser problem
//
#ifdef METHOD3
var.vt = VT_BSTR;
var.bstrVal = _T("file://c:\\toto.htm");
#endif
/*
hr = m_pHTMLPopup->show(a.Elem(),
lElemLeft, lElemTop,
lElemWidth, 100,
VARIANT_TRUE);
if (FAILED(hr))
goto Cleanup;
*/
Cleanup:
if (pDoc)
{
pDoc->Release();
}
if (bstrEvent)
{
SysFreeString(bstrEvent);
}
ReleaseInterface(pElem2);
ReleaseInterface(pElem);
ReleaseInterface(pMarkupSrv);
ReleaseInterface(pMarkupPStart);
ReleaseInterface(pMarkupPEnd);
ReleaseInterface(pBody);
ReleaseInterface(pHtml);
return hr;
}
// ========================================================================
// CEventSink::IDispatch
// ========================================================================
// The event sink's IDispatch interface is what gets called when events
// are fired.
//+------------------------------------------------------------------------
//
// Member: CCombobox::CEventSink::GetTypeInfoCount
// CCombobox::CEventSink::GetTypeInfo
// CCombobox::CEventSink::GetIDsOfNames
//
// Synopsis: We don't really need a nice IDispatch... this minimalist
// version does just plenty.
//
//-------------------------------------------------------------------------
STDMETHODIMP
CCombobox::CEventSink::GetTypeInfoCount(UINT* /*pctinfo*/)
{
return E_NOTIMPL;
}
STDMETHODIMP
CCombobox::CEventSink::GetTypeInfo(/* [in] */ UINT /*iTInfo*/,
/* [in] */ LCID /*lcid*/,
/* [out] */ ITypeInfo** /*ppTInfo*/)
{
return E_NOTIMPL;
}
STDMETHODIMP
CCombobox::CEventSink::GetIDsOfNames( REFIID riid,
OLECHAR** rgszNames,
UINT cNames,
LCID lcid,
DISPID* rgDispId)
{
return E_NOTIMPL;
}
//+------------------------------------------------------------------------
//
// Member: CCombobox::CEventSink::Invoke
//
// Synopsis: This gets called for all events on our object. (it was
// registered to do so in Init with attach_event.) It calls
// the appropriate parent functions to handle the events.
//
//-------------------------------------------------------------------------
STDMETHODIMP
CCombobox::CEventSink::Invoke( DISPID dispIdMember,
REFIID, LCID,
WORD wFlags,
DISPPARAMS* pDispParams,
VARIANT* pVarResult,
EXCEPINFO*,
UINT* puArgErr)
{
HRESULT hr = TRUE;
if (m_pParent && pDispParams && pDispParams->cArgs>=1)
{
if (pDispParams->rgvarg[0].vt == VT_DISPATCH)
{
IHTMLEventObj *pObj=NULL;
if (SUCCEEDED(pDispParams->rgvarg[0].pdispVal->QueryInterface(IID_IHTMLEventObj,
(void **)&pObj) && pObj))
{
BSTR bstrEvent=NULL;
pObj->get_type(&bstrEvent);
// user clicked one of our anchors
if (! StrCmpICW (bstrEvent, L"click"))
{
hr = m_pParent->ProcOnClick(this);
}
pObj->Release();
}
}
}
return hr;
}
//+------------------------------------------------------------------------
//
// Member: CCombobox::CEventSink
//
// Synopsis: This is used to allow communication between the parent class
// and the event sink class. The event sink will call the ProcOn*
// methods on the parent at the appropriate times.
//
//-------------------------------------------------------------------------
CCombobox::CEventSink::CEventSink (CCombobox * pParent)
{
m_pParent = pParent;
}
// ========================================================================
// CEventSink::IUnknown
// ========================================================================
// Vanilla IUnknown implementation for the event sink.
STDMETHODIMP
CCombobox::CEventSink::QueryInterface(REFIID riid, void ** ppUnk)
{
void * pUnk = NULL;
if (riid == IID_IDispatch)
pUnk = (IDispatch *) this;
if (riid == IID_IUnknown)
pUnk = (IUnknown *) this;
if (pUnk)
{
*ppUnk = pUnk;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG)
CCombobox::CEventSink::AddRef(void)
{
return ((IElementBehavior *)m_pParent)->AddRef();
}
STDMETHODIMP_(ULONG)
CCombobox::CEventSink::Release(void)
{
return ((IElementBehavior *)m_pParent)->Release();
}