📄 occsite.cpp
字号:
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include "occimpl.h"
#include "msdadc.h"
#ifdef AFX_OCC_SEG
#pragma code_seg(AFX_OCC_SEG)
#endif
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define new DEBUG_NEW
#define S_QUICKACTIVATED S_FALSE
#include "initguid.h"
#define DBINITCONSTANTS
#define INITGUID
DEFINE_GUID(IID_IDataSourceListener,0x7C0FFAB2L,0xCD84,0x11D0,0x94,0x9A,0x00,0xA0,0xC9,0x11,0x10,0xED);
DEFINE_GUID(IID_IDataSource,0x7c0ffab3L, 0xcd84, 0x11d0, 0x94, 0x9a, 0x00, 0xa0, 0xc9, 0x11, 0x10, 0xed);
/////////////////////////////////////////////////////////////////////////////
// COleControlSite
BEGIN_INTERFACE_MAP(COleControlSite, CCmdTarget)
INTERFACE_PART(COleControlSite, IID_IOleClientSite, OleClientSite)
INTERFACE_PART(COleControlSite, IID_IOleInPlaceSite, OleIPSite)
INTERFACE_PART(COleControlSite, IID_IOleControlSite, OleControlSite)
INTERFACE_PART(COleControlSite, IID_IDispatch, AmbientProps)
INTERFACE_PART(COleControlSite, IID_IBoundObjectSite, BoundObjectSite)
INTERFACE_PART(COleControlSite, IID_INotifyDBEvents, NotifyDBEvents)
INTERFACE_PART(COleControlSite, IID_IRowsetNotify, RowsetNotify)
END_INTERFACE_MAP()
COleControlSite::COleControlSite(COleControlContainer* pCtrlCont) :
m_pCtrlCont(pCtrlCont),
m_pWndCtrl(NULL),
m_nID((UINT)-1),
m_pObject(NULL),
m_pInPlaceObject(NULL),
m_pActiveObject(NULL),
m_dwEventSink(0),
m_dwPropNotifySink(0),
m_dwMiscStatus(0),
m_dwNotifyDBEvents(0),
m_pDataSourceControl(NULL),
m_pDSCSite(NULL),
m_defdispid(0),
m_dwType(0),
m_pBindings(NULL),
m_bIgnoreNotify(FALSE),
m_bIsDirty(FALSE)
{
memset(&m_varResult, 0, sizeof(VARIANT));
m_varResult.vt = VT_EMPTY;
}
COleControlSite::~COleControlSite()
{
delete m_pDataSourceControl;
DetachWindow();
DisconnectSink(m_iidEvents, m_dwEventSink);
DisconnectSink(IID_IPropertyNotifySink, m_dwPropNotifySink);
DisconnectSink(IID_INotifyDBEvents, m_dwNotifyDBEvents);
if (m_pInPlaceObject != NULL)
{
m_pInPlaceObject->InPlaceDeactivate();
m_pInPlaceObject->Release();
m_pInPlaceObject = NULL;
}
if (m_pActiveObject != NULL)
{
m_pActiveObject->Release();
m_pActiveObject = NULL;
}
if (m_pObject != NULL)
{
m_pObject->SetClientSite(NULL);
m_pObject->Close(OLECLOSE_NOSAVE);
m_pObject->Release();
m_pObject = NULL;
}
::VariantClear(&m_varResult);
BindProperty(DISPID_UNKNOWN, NULL); // gets rid of complex bindings
if (m_defdispid != 0 && m_pDSCSite != NULL &&
m_pDSCSite->m_pDataSourceControl != NULL)
{
// get rid of simple bindings
m_pDSCSite->m_pDataSourceControl->BindProp(this, FALSE);
}
}
BOOL COleControlSite::SetExtent()
{
CSize size(m_rect.Size());
CClientDC dc(NULL);
dc.DPtoHIMETRIC(&size);
HRESULT hr;
if (SUCCEEDED(hr = m_pObject->SetExtent(DVASPECT_CONTENT, (SIZEL*)&size)))
{
if (SUCCEEDED(m_pObject->GetExtent(DVASPECT_CONTENT, (SIZEL*)&size)))
{
dc.HIMETRICtoDP(&size);
m_rect.right = m_rect.left + size.cx;
m_rect.bottom = m_rect.top + size.cy;
}
}
return SUCCEEDED(hr);
}
HRESULT COleControlSite::CreateControl(CWnd* pWndCtrl, REFCLSID clsid,
LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, UINT nID,
CFile* pPersist, BOOL bStorage, BSTR bstrLicKey)
{
CRect rect2( rect );
CPoint pt;
CSize size;
pt = rect2.TopLeft();
size = rect2.Size();
return( CreateControl( pWndCtrl, clsid, lpszWindowName, dwStyle, &pt, &size,
nID, pPersist, bStorage, bstrLicKey ) );
}
HRESULT COleControlSite::CreateControl(CWnd* pWndCtrl, REFCLSID clsid,
LPCTSTR lpszWindowName, DWORD dwStyle, const POINT* ppt, const SIZE* psize,
UINT nID, CFile* pPersist, BOOL bStorage, BSTR bstrLicKey)
{
HRESULT hr = E_FAIL;
m_hWnd = NULL;
CSize size;
// Connect the OLE Control with its proxy CWnd object
if (pWndCtrl != NULL)
{
ASSERT(pWndCtrl->m_pCtrlSite == NULL);
m_pWndCtrl = pWndCtrl;
pWndCtrl->m_pCtrlSite = this;
}
// Initialize OLE, if necessary
_AFX_THREAD_STATE* pState = AfxGetThreadState();
if (!pState->m_bNeedTerm && !AfxOleInit())
return hr;
if (SUCCEEDED(hr = CreateOrLoad(clsid, pPersist, bStorage, bstrLicKey)))
{
ASSERT(m_pObject != NULL);
m_nID = nID;
if (psize == NULL)
{
// If psize is NULL, ask the object how big it wants to be.
CClientDC dc(NULL);
m_pObject->GetExtent(DVASPECT_CONTENT, &size);
dc.HIMETRICtoDP(&size);
m_rect = CRect(*ppt, size);
}
else
{
m_rect = CRect(*ppt, *psize);
}
m_dwStyleMask = WS_GROUP | WS_TABSTOP;
if (m_dwMiscStatus & OLEMISC_ACTSLIKEBUTTON)
m_dwStyleMask |= BS_DEFPUSHBUTTON;
if (m_dwMiscStatus & OLEMISC_INVISIBLEATRUNTIME)
dwStyle &= ~WS_VISIBLE;
m_dwStyle = dwStyle & m_dwStyleMask;
// If control wasn't quick-activated, then connect sinks now.
if (hr != S_QUICKACTIVATED)
{
m_dwEventSink = ConnectSink(m_iidEvents, &m_xEventSink);
m_dwPropNotifySink = ConnectSink(IID_IPropertyNotifySink,
&m_xPropertyNotifySink);
}
m_dwNotifyDBEvents = ConnectSink(IID_INotifyDBEvents, &m_xNotifyDBEvents);
// Now that the object has been created, attempt to
// in-place activate it.
SetExtent();
if (SUCCEEDED(hr = m_pObject->QueryInterface(IID_IOleInPlaceObject,
(LPVOID*)&m_pInPlaceObject)))
{
if (dwStyle & WS_VISIBLE)
{
// control is visible: just activate it
hr = DoVerb(OLEIVERB_INPLACEACTIVATE);
}
else
{
// control is not visible: activate off-screen, hide, then move
m_rect.OffsetRect(-32000, -32000);
if (SUCCEEDED(hr = DoVerb(OLEIVERB_INPLACEACTIVATE)) &&
SUCCEEDED(hr = DoVerb(OLEIVERB_HIDE)))
{
m_rect.OffsetRect(32000, 32000);
hr = m_pInPlaceObject->SetObjectRects(m_rect, m_rect);
}
}
}
else
{
TRACE1("IOleInPlaceObject not supported on OLE control (dialog ID %d).\n", nID);
TRACE1(">>> Result code: 0x%08lx\n", hr);
}
if (SUCCEEDED(hr))
GetControlInfo();
// if QueryInterface or activation failed, cleanup everything
if (FAILED(hr))
{
if (m_pInPlaceObject != NULL)
{
m_pInPlaceObject->Release();
m_pInPlaceObject = NULL;
}
DisconnectSink(m_iidEvents, m_dwEventSink);
DisconnectSink(IID_IPropertyNotifySink, m_dwPropNotifySink);
DisconnectSink(IID_INotifyDBEvents, m_dwNotifyDBEvents);
m_dwEventSink = 0;
m_dwPropNotifySink = 0;
m_dwNotifyDBEvents = 0;
m_pObject->Release();
m_pObject = NULL;
}
}
if (SUCCEEDED(hr))
{
AttachWindow();
ASSERT(m_hWnd != NULL);
// Initialize the control's Caption or Text property, if any
if (lpszWindowName != NULL)
SetWindowText(lpszWindowName);
// Initialize styles
ModifyStyle(0, m_dwStyle | (dwStyle & (WS_DISABLED|WS_BORDER)), 0);
}
return hr;
}
BOOL COleControlSite::DestroyControl()
{
ASSERT(m_hWnd != NULL); // was control ever successfully created?
m_pCtrlCont->m_siteMap.RemoveKey(m_hWnd);
//VBBUG: VB controls will crash if IOleObject::Close is called on them
// when they have focus (and unfortunately, deactivating them does not
// always move the focus). To work around this problem, we always hide
// the control before closing it.
ShowWindow(SW_HIDE);
// Now it is safe to close the control.
delete this;
return TRUE;
}
AFX_STATIC HRESULT AFXAPI _AfxCoCreateInstanceLic(REFCLSID clsid, LPUNKNOWN pUnkOuter,
DWORD dwClsCtx, REFIID iid, LPVOID* ppv, BSTR bstrLicKey)
{
HRESULT hr;
if (bstrLicKey == NULL)
{
LPCLASSFACTORY pClassFactory = NULL;
if (SUCCEEDED(hr = CoGetClassObject(clsid, dwClsCtx, NULL,
IID_IClassFactory, (void**)&pClassFactory)))
{
ASSERT(pClassFactory != NULL);
hr = pClassFactory->CreateInstance(pUnkOuter, iid, ppv);
pClassFactory->Release();
}
}
else
{
LPCLASSFACTORY2 pClassFactory = NULL;
if (SUCCEEDED(hr = CoGetClassObject(clsid, dwClsCtx, NULL,
IID_IClassFactory2, (void**)&pClassFactory)))
{
ASSERT(pClassFactory != NULL);
hr = pClassFactory->CreateInstanceLic(pUnkOuter, NULL, iid,
bstrLicKey, ppv);
pClassFactory->Release();
}
}
return hr;
}
AFX_STATIC_DATA const struct { DISPID dwDispID; DWORD dwFlag; } _afxAmbients[] =
{
{ DISPID_AMBIENT_USERMODE, QACONTAINER_USERMODE },
{ DISPID_AMBIENT_UIDEAD, QACONTAINER_UIDEAD },
{ DISPID_AMBIENT_SHOWGRABHANDLES, QACONTAINER_SHOWGRABHANDLES },
{ DISPID_AMBIENT_SHOWHATCHING, QACONTAINER_SHOWHATCHING },
{ DISPID_AMBIENT_DISPLAYASDEFAULT, QACONTAINER_DISPLAYASDEFAULT },
{ DISPID_AMBIENT_AUTOCLIP, QACONTAINER_AUTOCLIP },
{ DISPID_AMBIENT_MESSAGEREFLECT, QACONTAINER_MESSAGEREFLECT },
{ DISPID_AMBIENT_SUPPORTSMNEMONICS, QACONTAINER_SUPPORTSMNEMONICS },
};
BOOL COleControlSite::QuickActivate()
{
BOOL bQuickActivated = FALSE;
IQuickActivate* pQuick = NULL;
if (SUCCEEDED(m_pObject->QueryInterface(IID_IQuickActivate,
reinterpret_cast<void**>(&pQuick))))
{
ASSERT(pQuick != NULL);
// Initialize QACONTAINER structure.
QACONTAINER qaContainer;
qaContainer.cbSize = sizeof(QACONTAINER);
qaContainer.pClientSite = &m_xOleClientSite;
qaContainer.pAdviseSink = NULL;
qaContainer.pPropertyNotifySink = &m_xPropertyNotifySink;
qaContainer.pUnkEventSink = &m_xEventSink;
qaContainer.pUndoMgr = NULL;
qaContainer.hpal = NULL;
qaContainer.pBindHost = NULL;
// Fill ambient property values in QACONTAINER.
COleVariant var;
CWnd* pWndContain = m_pCtrlCont->m_pWnd;
qaContainer.dwAmbientFlags = 0;
for (int i = 0; i < _countof(_afxAmbients); i++)
{
pWndContain->OnAmbientProperty(this, _afxAmbients[i].dwDispID, &var);
if (V_BOOL(&var))
qaContainer.dwAmbientFlags |= _afxAmbients[i].dwFlag;
}
pWndContain->OnAmbientProperty(this, DISPID_AMBIENT_FORECOLOR, &var);
qaContainer.colorFore = V_I4(&var);
pWndContain->OnAmbientProperty(this, DISPID_AMBIENT_BACKCOLOR, &var);
qaContainer.colorBack = V_I4(&var);
pWndContain->OnAmbientProperty(this, DISPID_AMBIENT_APPEARANCE, &var);
qaContainer.dwAppearance = V_I2(&var);
pWndContain->OnAmbientProperty(this, DISPID_AMBIENT_LOCALEID, &var);
qaContainer.lcid = V_I4(&var);
pWndContain->OnAmbientProperty(this, DISPID_AMBIENT_FONT, &var);
if (FAILED(V_DISPATCH(&var)->QueryInterface(IID_IFont,
reinterpret_cast<void**>(&qaContainer.pFont))))
{
qaContainer.pFont = NULL;
}
// Initialize QACONTROL structure.
QACONTROL qaControl;
qaControl.cbSize = sizeof(QACONTROL);
// Do the quick activation.
if (SUCCEEDED(pQuick->QuickActivate(&qaContainer, &qaControl)))
{
// Extract return values from QACONTROL structure.
m_dwMiscStatus = qaControl.dwMiscStatus;
m_dwEventSink = qaControl.dwEventCookie;
m_dwPropNotifySink = qaControl.dwPropNotifyCookie;
bQuickActivated = TRUE;
}
pQuick->Release();
if (qaContainer.pFont != NULL)
qaContainer.pFont->Release();
}
return bQuickActivated;
}
HRESULT COleControlSite::CreateOrLoad(REFCLSID clsid, CFile* pFile,
BOOL bStorage, BSTR bstrLicKey)
{
ASSERT(m_pObject == NULL);
#ifdef _DEBUG
OLECHAR wszClsid[40];
StringFromGUID2(clsid, wszClsid, 40);
#endif //_DEBUG
HRESULT hr;
if (FAILED(hr = _AfxCoCreateInstanceLic(clsid, NULL,
CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, IID_IOleObject,
(void**)&m_pObject, bstrLicKey)))
{
TRACE1("CoCreateInstance of OLE control %ls failed.\n", wszClsid);
TRACE1(">>> Result code: 0x%08lx\n", hr);
TRACE0(">>> Is the control is properly registered?\n");
return hr;
}
LPPERSISTSTREAMINIT pPersStm = NULL;
LPPERSISTSTORAGE pPersStg = NULL;
LPPERSISTMEMORY pPersMem = NULL;
GetEventIID(&m_iidEvents);
// Try to quick-activate first
BOOL bQuickActivated = QuickActivate();
if (!bQuickActivated)
{
m_pObject->GetMiscStatus(DVASPECT_CONTENT, &m_dwMiscStatus);
// set client site first, if appropriate
if (m_dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)
{
if (FAILED(hr = m_pObject->SetClientSite(&m_xOleClientSite)))
{
TRACE1("SetClientSite on OLE control %ls failed.\n", wszClsid);
TRACE1(">>> Result code: 0x%08lx\n", hr);
goto CreateOrLoadFailed;
}
}
}
ASSERT(!bStorage || pFile != NULL);
// initialize via IPersistMemory (direct buffering)
if (pFile != NULL && !bStorage &&
SUCCEEDED(m_pObject->QueryInterface(IID_IPersistMemory, (void**)&pPersMem)) &&
pFile->GetBufferPtr(CFile::bufferCheck) != 0)
{
ASSERT(pPersMem != NULL);
// file supports direct buffering, get its buffer pointer and size
LPVOID pvBuffer = NULL;
LPVOID pvEnd;
ULONG cbBuffer = pFile->GetBufferPtr(
CFile::bufferRead, (UINT)-1, &pvBuffer, &pvEnd);
ASSERT(((LPBYTE)pvEnd - (LPBYTE)pvBuffer) == (int)cbBuffer);
// and then load it directly
hr = pPersMem->Load(pvBuffer, cbBuffer);
pPersMem->Release();
pPersMem = NULL;
if (FAILED(hr))
goto CreateOrLoadFailed;
}
// initialize via IPersistStreamInit
else if (!bStorage && SUCCEEDED(m_pObject->QueryInterface(
IID_IPersistStreamInit, (void**)&pPersStm)))
{
ASSERT(pPersStm != NULL);
if (pFile == NULL)
{
// just call InitNew
hr = pPersStm->InitNew();
}
else
{
// open an IStream on the data and pass it to Load
CArchive ar(pFile, CArchive::load);
CArchiveStream stm(&ar);
hr = pPersStm->Load(&stm);
}
pPersStm->Release();
if (FAILED(hr))
{
TRACE1("InitNew or Load on OLE control %ls failed.\n", wszClsid);
TRACE1(">>> Result code: 0x%08lx\n", hr);
goto CreateOrLoadFailed;
}
}
// initialize via IPersistStorage
else if (SUCCEEDED(m_pObject->QueryInterface(
IID_IPersistStorage, (void**)&pPersStg)))
{
ASSERT(pPersStg != NULL);
if (pFile == NULL)
{
// create a scratch IStorage and pass it to InitNew
LPLOCKBYTES pLockBytes = NULL;
if (SUCCEEDED(hr = CreateILockBytesOnHGlobal(NULL, TRUE,
&pLockBytes)))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -