213 lines
5.4 KiB
C++
213 lines
5.4 KiB
C++
|
#include "shellprv.h"
|
||
|
#include "duiview.h"
|
||
|
#include "duihost.h"
|
||
|
|
||
|
|
||
|
// DUIAxHost Initialization
|
||
|
|
||
|
HRESULT DUIAxHost::Create(UINT nCreate, UINT nActive, OUT DUIAxHost** ppElement)
|
||
|
{
|
||
|
*ppElement = NULL;
|
||
|
|
||
|
DUIAxHost* pe = HNewAndZero<DUIAxHost>();
|
||
|
if (!pe)
|
||
|
return E_OUTOFMEMORY;
|
||
|
|
||
|
HRESULT hr = pe->Initialize(nCreate, nActive);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
pe->Destroy();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*ppElement = pe;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
HWND DUIAxHost::CreateHWND(HWND hwndParent)
|
||
|
{
|
||
|
return CreateWindowEx(0, CAxWindow::GetWndClassName(), NULL,
|
||
|
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
|
||
|
0, 0, 0, 0, hwndParent, NULL, NULL, NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT DUIAxHost::SetSite(IUnknown* punkSite)
|
||
|
{
|
||
|
CComPtr<IUnknown> spHost;
|
||
|
HRESULT hr = AtlAxGetHost(GetHWND(), &spHost);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = IUnknown_SetSite(spHost, punkSite);
|
||
|
}
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
void DUIAxHost::OnDestroy()
|
||
|
{
|
||
|
SetSite(NULL);
|
||
|
HWNDHost::OnDestroy();
|
||
|
ATOMICRELEASE(_pOleObject);
|
||
|
}
|
||
|
|
||
|
bool DUIAxHost::OnNotify(UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT* plRet)
|
||
|
{
|
||
|
switch (nMsg)
|
||
|
{
|
||
|
case WM_DESTROY:
|
||
|
SetSite(NULL);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return HWNDHost::OnNotify(nMsg, wParam, lParam, plRet);
|
||
|
}
|
||
|
|
||
|
HRESULT DUIAxHost::AttachControl(IUnknown* punkObject)
|
||
|
{
|
||
|
if (NULL == GetHWND())
|
||
|
return E_UNEXPECTED;
|
||
|
|
||
|
if (NULL == punkObject)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
ATOMICRELEASE(_pOleObject);
|
||
|
|
||
|
HRESULT hr = punkObject->QueryInterface(IID_PPV_ARG(IOleObject, &_pOleObject));
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CComPtr<IUnknown> spUnk;
|
||
|
hr = AtlAxGetHost(GetHWND(), &spUnk);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
CComPtr<IAxWinHostWindow> spDUIAxHostWindow;
|
||
|
hr = spUnk->QueryInterface(&spDUIAxHostWindow);
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = spDUIAxHostWindow->AttachControl(punkObject, GetHWND());
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////
|
||
|
// DUIAxHost Rendering
|
||
|
|
||
|
SIZE DUIAxHost::GetContentSize(int dConstW, int dConstH, Surface* psrf)
|
||
|
{
|
||
|
SIZE size = { 0, 0 };
|
||
|
|
||
|
// Ask the attached ActiveX control for its preferred size
|
||
|
if (NULL != _pOleObject)
|
||
|
{
|
||
|
SIZEL sizeT;
|
||
|
if (SUCCEEDED(_pOleObject->GetExtent(DVASPECT_CONTENT, &sizeT)))
|
||
|
{
|
||
|
int dpiX;
|
||
|
int dpiY;
|
||
|
|
||
|
switch (psrf->GetType())
|
||
|
{
|
||
|
case Surface::stDC:
|
||
|
{
|
||
|
HDC hDC = CastHDC(psrf);
|
||
|
dpiX = GetDeviceCaps(hDC, LOGPIXELSX);
|
||
|
dpiY = GetDeviceCaps(hDC, LOGPIXELSX);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
#ifdef GADGET_ENABLE_GDIPLUS
|
||
|
case Surface::stGdiPlus:
|
||
|
{
|
||
|
Gdiplus::Graphics * pgpgr = CastGraphics(psrf);
|
||
|
dpiX = (int)pgpgr->GetDpiX();
|
||
|
dpiY = (int)pgpgr->GetDpiY();
|
||
|
}
|
||
|
break;
|
||
|
#endif
|
||
|
default:
|
||
|
dpiX = dpiY = 96;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Convert from HIMETRIC to pixels
|
||
|
size.cx = (MAXLONG == sizeT.cx) ? MAXLONG : MulDiv(sizeT.cx, dpiX, 2540);
|
||
|
size.cy = (MAXLONG == sizeT.cy) ? MAXLONG : MulDiv(sizeT.cy, dpiY, 2540);
|
||
|
|
||
|
if (-1 != dConstW && size.cx > dConstW) size.cx = dConstW;
|
||
|
if (-1 != dConstH && size.cy > dConstH) size.cy = dConstH;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return size;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////
|
||
|
// DUIAxHost Keyboard navigation
|
||
|
|
||
|
void DUIAxHost::SetKeyFocus()
|
||
|
{
|
||
|
FakeTabEvent();
|
||
|
|
||
|
// No matter what, we should continue with standard DUI operations.
|
||
|
Element::SetKeyFocus();
|
||
|
}
|
||
|
|
||
|
void DUIAxHost::OnEvent(Event* pEvent)
|
||
|
{
|
||
|
bool fHandled = false;
|
||
|
|
||
|
if (pEvent->nStage == GMF_DIRECT && pEvent->uidType == Element::KeyboardNavigate) {
|
||
|
int iNavDir = ((KeyboardNavigateEvent*) pEvent)->iNavDir;
|
||
|
if (((iNavDir & NAV_NEXT) == NAV_NEXT) || ((iNavDir & NAV_PREV) == NAV_PREV)) {
|
||
|
fHandled = FakeTabEvent();
|
||
|
} else {
|
||
|
// Handle other types of navigation here... (home/end/etc)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Continue with standard DUI operation if the navigation event wasn't handled
|
||
|
// by our contained ActiveX control.
|
||
|
if (!fHandled) {
|
||
|
Element::OnEvent(pEvent);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool DUIAxHost::FakeTabEvent()
|
||
|
{
|
||
|
bool fHandled = false;
|
||
|
|
||
|
MSG msg;
|
||
|
|
||
|
ZeroMemory(&msg, sizeof(msg));
|
||
|
msg.message = WM_KEYDOWN;
|
||
|
msg.wParam = VK_TAB;
|
||
|
msg.lParam = 1;
|
||
|
|
||
|
// Note: we probably should do something to respect navoigating forward
|
||
|
// or backwards. The ActiveX control needs to know if it should activate
|
||
|
// the first or last tab stop. For now it will only reliably
|
||
|
// activate the first one. If it checks the keyboard Shift state
|
||
|
// it will probably get it right, but not 100% guaranteed.
|
||
|
|
||
|
if(SendMessage(GetHWND(), WM_FORWARDMSG, 0, (LPARAM)&msg)) {
|
||
|
fHandled = true;
|
||
|
}
|
||
|
|
||
|
return fHandled;
|
||
|
}
|
||
|
|
||
|
// Define class info with type and base type, set static class pointer
|
||
|
IClassInfo* DUIAxHost::Class = NULL;
|
||
|
HRESULT DUIAxHost::Register()
|
||
|
{
|
||
|
return ClassInfo<DUIAxHost,HWNDHost>::Register(L"DUIAxHost", NULL, 0);
|
||
|
}
|
||
|
|
||
|
HRESULT DUIAxHost::GetAccessibleImpl(IAccessible ** ppAccessible)
|
||
|
{
|
||
|
return CreateStdAccessibleObject(GetHWND(), OBJID_CLIENT, IID_PPV_ARG(IAccessible, ppAccessible));
|
||
|
}
|