#include "project.hpp" #pragma hdrstop #include "contain.hpp" #include "csite.hpp" #include "helpers.hpp" // {C71E9420-E82F-11ce-B6CF-00AA00A74DAF} static const GUID CLSID_ScriptIntegrator = { 0xc71e9420, 0xe82f, 0x11ce, { 0xb6, 0xcf, 0x0, 0xaa, 0x0, 0xa7, 0x4d, 0xaf } }; // {0BB43480-E20B-11ce-B6CF-00AA00A74DAF} static const GUID IID_IScriptIntegration = { 0xbb43480, 0xe20b, 0x11ce, { 0xb6, 0xcf, 0x0, 0xaa, 0x0, 0xa7, 0x4d, 0xaf } }; CSite::CSite(HText *text) { ASSERT(text != NULL); ASSERT(IsWindow(text->tw->win)); _docWnd = text->tw->win; _dwRef = 0L; // Set our interfaces to NULL _pIOleClientSite = NULL; _pIOleControlSite = NULL; _pIAdviseSink = NULL; _pIOleInPlaceSite = NULL; _pXObject = NULL; _pIOleDispatchAmbientProps = NULL; // Set the script integration interface pointer to NULL. _pIntegrator = NULL; } CSite::~CSite() { ASSERT(_pIAdviseSink != NULL && _pIAdviseSink->GetRef() == 0); ASSERT(_pIOleControlSite != NULL && _pIOleControlSite->GetRef() == 0); ASSERT(_pIOleClientSite != NULL && _pIOleClientSite->GetRef() == 0); ASSERT(_pIOleInPlaceSite != NULL && _pIOleInPlaceSite->GetRef() == 0); ASSERT(_pIOleDispatchAmbientProps != NULL && _pIOleDispatchAmbientProps->GetRef() == 0); // No need to delete _pXObject. It is a special interface that handles // reference counting and deletes itself when the ref count goes to zero. SAFEDELETE(_pIAdviseSink); SAFEDELETE(_pIOleClientSite); SAFEDELETE(_pIOleControlSite); SAFEDELETE(_pIOleInPlaceSite); SAFEDELETE(_pIOleDispatchAmbientProps); } HRESULT CSite::InitializeSite(const char *name) { HRESULT hr = E_OUTOFMEMORY; _pIAdviseSink = new (CAdviseSink(this, this)); if (_pIAdviseSink == NULL) goto cleanup; _pIOleClientSite = new (COleClientSite(this, this)); if (_pIOleClientSite == NULL) goto cleanup; _pIOleControlSite = new (COleControlSite(this, this)); if (_pIOleControlSite == NULL) goto cleanup; _pIOleInPlaceSite = new (COleInPlaceSite(this, this)); if (_pIOleInPlaceSite == NULL) goto cleanup; _pXObject = new (CXObject(this, name)); if (_pXObject == NULL) goto cleanup; _pIOleDispatchAmbientProps = new (CAmbientDispatch( this, this)); if (_pIOleDispatchAmbientProps == NULL) goto cleanup; g_Container->AddSite(this, &_SiteCookie); AddRef(); // Stay around, jack! return S_OK; cleanup: SAFERELEASE(_pIAdviseSink); SAFERELEASE(_pIOleClientSite); SAFERELEASE(_pIOleControlSite); SAFERELEASE(_pIOleInPlaceSite); SAFERELEASE(_pXObject); SAFERELEASE(_pIOleDispatchAmbientProps); return hr; } // IUnknown methods STDMETHODIMP_(ULONG) CSite::AddRef(void) { return ++_dwRef; } STDMETHODIMP_(ULONG) CSite::Release(void) { if (--_dwRef == 0) { delete this; return 0; } return _dwRef; } STDMETHODIMP CSite::QueryInterface(REFIID riid, LPVOID *ppvObj) { // ppvObj must not be NULL ASSERT(ppvObj != NULL); if (ppvObj == NULL) return E_INVALIDARG; *ppvObj = NULL; if (IsEqualIID(riid, IID_IUnknown)) *ppvObj = this; else if (IsEqualIID(riid, IID_IOleClientSite)) *ppvObj = _pIOleClientSite; else if (IsEqualIID(riid, IID_IOleControlSite)) *ppvObj = _pIOleControlSite; else if (IsEqualIID(riid, IID_IAdviseSink)) *ppvObj = _pIAdviseSink; else if (IsEqualIID(riid, IID_IOleInPlaceSite)) *ppvObj = _pIOleInPlaceSite; else if (IsEqualIID(riid, IID_IDispatch)) *ppvObj = _pIOleDispatchAmbientProps; else return g_Container->QueryInterface(riid, ppvObj); // Delegate to global container object if (*ppvObj != NULL) // Should always be non-NULL at this point, but just to be safe... ((LPUNKNOWN)*ppvObj)->AddRef(); return S_OK; } HRESULT CSite::Destroy() { HRESULT hr = S_OK; // Deactivate the control _pXObject->Deactivate(); _pXObject->Destroy(); g_Container->DeleteSite(&_SiteCookie); Release(); // Decrement reference count on site object. return hr; } HRESULT CSite::CreateEmbedding(CLSID clsid) { // BUGBUG: Need to check to see if this is really a control before aggregating with x object... if (SUCCEEDED(Mpolevtbl->CoCreateInstance(clsid, _pXObject, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)_pXObject->GetInnerUnknown()))) { _pXObject->Initialize(); return _pXObject->SetClientSite(_pIOleClientSite); // Control will addref the client site interface } else return E_FAIL; } HRESULT CSite::ConnectEvents(const char* pSinkID, const char* progid) { ASSERT((pSinkID != NULL) || (progid != NULL)); // Got to have one or the other... HRESULT hr; CLSID clsid; if (progid != NULL) // We prefer a ProgID hr = ConvertANSIProgIDtoCLSID(progid, &clsid); else hr = ConvertANSItoCLSID(pSinkID, &clsid); if (FAILED(hr)) { DBGOUT("Could not convert SINK id to CLSID"); return hr; } LPDISPATCH pEventSink = NULL; // Instantiate the event sink if SUCCEEDED(Mpolevtbl->CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDispatch, (void **)&pEventSink)) { // Load up the glue DLL hr = Mpolevtbl->CoCreateInstance(CLSID_ScriptIntegrator, NULL, CLSCTX_INPROC_SERVER, IID_IScriptIntegration, (void **)&_pIntegrator); if (SUCCEEDED(hr)) hr = _pIntegrator->IntegrateUI(g_Container->_pIOleContainer, pEventSink); } else DBGOUT("Could not load script DLL"); return hr; } void HText_addEmbed(HText *text, const char* pszClsid, const char* events, const char * height, const char *name, const char* progid, const char* properties, const char* propertysrc, const char * sink, const char* src, const char* width) { ASSERT(text != NULL); ASSERT(pszClsid != NULL); // Need to have a CLSID to create!! InitializeContainer(); PCSite pSite = new (CSite(text)); CLSID clsid; ConvertANSItoCLSID(pszClsid, &clsid); // Create a new C++ site object if (pSite == NULL) return; // Couldn't allocate memory for site object else pSite->InitializeSite(name); // Initialize the site object. if (SUCCEEDED(pSite->CreateEmbedding(clsid))) { pSite->_pXObject->Activate(); // If this embedding sources out events, hook 'em up! // if (sink || progid) pSite->ConnectEvents(sink, progid); } else { if (pSite) delete pSite; return; // Couldn't create embedded object } // If successful, add a new form element; if (pSite) { HText_add_element(text, ELE_EMBED); text->bOpen = FALSE; text->w3doc->aElements[text->iElement].form = (struct _form_element *) GTR_MALLOC(sizeof(struct _form_element)); memset(text->w3doc->aElements[text->iElement].form, 0, sizeof(struct _form_element)); text->w3doc->aElements[text->iElement].form->iBeginForm = text->iBeginForm; text->w3doc->aElements[text->iElement].form->pSite = pSite; } } // Callback for destroying site object. After this function executes, the // site object is **gone**. HRESULT CloseSite(void * ptr) { // ptr is really a pointer to a CSite class instance ASSERT(ptr != NULL); PCSite pSite = (PCSite) ptr; pSite->Destroy(); return S_OK; } #ifdef FEATURE_IMG_THREADS #define HIDDEN_X_POS 10000 #define HIDDEN_Y_POS 0 BOOL bUnformatted = TRUE; int nLastGoodElement = -1; int nLastLine; #endif // Callback for positioning control during layout. HRESULT SetEmbeddedObjectRect(BOOL bUnformatted, struct Mwin *tw, struct _element *el) { PCSite pSite = (PCSite) el->form->pSite; ASSERT(pSite != NULL); LPOLEOBJECT pObj = pSite->_pXObject->GetObject(); LPOLEINPLACEOBJECT pOIPO = NULL; if (pObj != NULL) { pObj->QueryInterface(IID_IOleInPlaceObject, (void **)&pOIPO); if (pOIPO) { RECT rSize; SetRectEmpty(&rSize); SIZEL *size = pSite->_pXObject->GetSize(); SetRect(&rSize, #ifdef FEATURE_IMG_THREADS bUnformatted ? HIDDEN_X_POS:el->r.left - tw->offl, bUnformatted ? HIDDEN_Y_POS:el->r.top - tw->offt, #else el->r.left - tw->offl, el->r.top - tw->offt, #endif (el->r.left + size->cx), (el->r.top + size->cy) ); pOIPO->SetObjectRects(&rSize, NULL); CopyRect(pSite->_pXObject->GetRect(), &rSize); SAFERELEASE(pOIPO); } SAFERELEASE(pObj); } return S_OK; } struct _line { #ifdef WIN32 HDC hdc; /* working var, not really related to a line */ #endif int nLineNum; int iFirstElement; /* in */ int iLastElement; /* out */ RECT r; /* left, right, and top go in, bottom comes out */ int baseline; /* calculated */ int leading; /* out */ int nWSBelow; /* Minimum whitespace below the line */ int nWSAbove; /* Whitespace above current line */ int gIndentLevel; int gRightIndentLevel; int Flags; int deferedFloatImgs[10]; // array of defered floating images int numDeferedFloatImgs; // count of defered floating images }; /* FormatEmbbedObject fills in the r structure which indicated the size of the element. This is later used to format each line. This code is called (and essentially copied) from the case statement in x_format_one_line in the file reformat.c */ HRESULT FormatEmbeddedObject(struct _element* pel, int *cThings, BOOL *bNeedsAdjust, int right_margin, struct _line * line, int *x, int *done, int prev_i) { ASSERT(pel != NULL && cThings != NULL && bNeedsAdjust != NULL); ASSERT(pel->form != NULL); ASSERT(pel->form->pSite != NULL); PCSite pSite = (PCSite)pel->form->pSite; if (pel->form->pSite == NULL) return E_INVALIDARG; /* For printing, form controls need to be scaled too { float fScale; if (pdoc->pStyles->image_res != 72) { fScale = (float) ((float) pdoc->pStyles->image_res / 96.0); siz.cx = (long) (siz.cx * fScale); siz.cy = (long) (siz.cy * fScale); } } */ SIZE *size = pSite->_pXObject->GetSize(); if ((!*cThings) || ((*x + size->cx) <= right_margin)) { // Make sure the rectangle is initialized. Shouldn't matter, but hey!! SetRectEmpty(&pel->r); pel->r.left = *x; pel->r.right = pel->r.left + size->cx; pel->r.top = line->r.top; pel->r.bottom = pel->r.top + size->cy; // // Baseline adjusts by 2 because of 3D effect on window controls. // Note: This currently isn't used because ALIGN_MIDDLE is always set. // pel->baseline = pel->r.bottom - 2; pel->alignment = ALIGN_MIDDLE; *x += (size->cx); if (line->r.bottom < pel->r.bottom) { line->r.bottom = pel->r.bottom; } *bNeedsAdjust = TRUE; *cThings++; XX_DMsg(DBG_TEXT, ("FORM CONTROL: cThings -> %d\n", *cThings)); } else { line->iLastElement = prev_i; *done = 1; } return S_OK; } HRESULT ShowAllEmbeddings(struct _www *w3doc, struct Mwin *tw, int nCmdShow) { if (w3doc->elementCount) { for (int i = 0; i >= 0; i = w3doc->aElements[i].next) { if (w3doc->aElements[i].form) { if (w3doc->aElements[i].form->pSite) { // We've got an embedding here, folks. PCSite pSite = (PCSite)w3doc->aElements[i].form->pSite; // There is a new doc window pSite->_docWnd = tw->win; if (nCmdShow == SW_HIDE) pSite->_pXObject->Hide(); else if (nCmdShow == SW_SHOW) pSite->_pXObject->Show(); } } } } return S_OK; }