Windows2003-3790/termsrv/newclient/clshell/axhostwnd.cpp
2020-09-30 16:53:55 +02:00

600 lines
16 KiB
C++

//
// axhostwnd.cpp: ActiveX control host window
// (For ts activeX control)
//
// Copyright Microsoft Corportation 2000
// (nadima)
//
#include "stdafx.h"
#define TRC_GROUP TRC_GROUP_UI
#define TRC_FILE "axhostwnd.cpp"
#include <atrcapi.h>
#define TSC_AX_HOSTWND_CLS TEXT("TSCAXHOST")
#define TSC_CONTROL_DLL TEXT("mstscax.dll")
#include "axhostwnd.h"
#ifndef OS_WINCE
#include "ntverp.h"
#else
#include "ceconfig.h"
#endif
CAxHostWnd::CAxHostWnd(CContainerWnd* pParentWnd) : _pParentWnd(pParentWnd)
{
DC_BEGIN_FN("CAxHostWnd");
_hWnd = NULL;
_pTsc = NULL;
_cRef = 1;
_hLib = NULL;
_piEventSink = NULL;
_piOleClientSite = NULL;
_piOleInPlaceSiteEx = NULL;
_piOleObject = NULL;
_piOleInPlaceActiveObject = NULL;
_piOleInPlaceObject = NULL;
_dwConCookie = 0;
TRC_ASSERT(_pParentWnd,(TB,_T("_pParentWnd not set")));
DC_END_FN();
}
CAxHostWnd::~CAxHostWnd()
{
DC_BEGIN_FN("~CAxHostWnd");
TRC_ASSERT(_piEventSink == NULL,(TB,_T("Exit without cleanup")));
TRC_ASSERT(_piOleClientSite == NULL,(TB,_T("Exit without cleanup")));
TRC_ASSERT(_piOleInPlaceSiteEx == NULL,(TB,_T("Exit without cleanup")));
TRC_ASSERT(_piOleObject == NULL,(TB,_T("Exit without cleanup")));
TRC_ASSERT(_piOleInPlaceActiveObject == NULL,(TB,_T("Exit without cleanup")));
TRC_ASSERT(_piOleInPlaceObject == NULL,(TB,_T("Exit without cleanup")));
TRC_ASSERT(_pTsc == NULL,(TB,_T("Exit without cleanup")));
DC_END_FN();
}
STDMETHODIMP CAxHostWnd::QueryInterface( REFIID riid, void ** ppv )
{
DC_BEGIN_FN("QueryInterface");
TRC_ASSERT(ppv != NULL,(TB,_T("ppv null")));
TRC_ASSERT(_piOleClientSite != NULL,
(TB,_T("QI needs IOleClientSite object")));
TRC_ASSERT(_piOleInPlaceSiteEx != NULL,
(TB,_T("QI needs _piOleInPlaceSiteEx object")));
if (ppv)
{
*ppv = NULL;
}
else
{
return E_INVALIDARG;
}
if (IID_IUnknown == riid)
*ppv = this;
else if (IID_IOleClientSite == riid)
*ppv = (void *)_piOleClientSite;
else if (IID_IOleInPlaceSiteEx == riid)
*ppv = (void *)_piOleInPlaceSiteEx;
if (NULL != *ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
return NOERROR;
}
DC_END_FN();
return ResultFromScode(E_NOINTERFACE);
}
STDMETHODIMP_(ULONG) CAxHostWnd::AddRef(void)
{
return InterlockedIncrement(&_cRef);
}
STDMETHODIMP_(ULONG) CAxHostWnd::Release(void)
{
if (0L != InterlockedDecrement(&_cRef))
{
return _cRef;
}
delete this;
return 0L;
}
CAxHostWnd::Init()
{
DC_BEGIN_FN("Init");
_piOleClientSite = new COleClientSite((IUnknown *)this);
if (!_piOleClientSite)
{
Cleanup();
return FALSE;
}
_piOleClientSite->AddRef();
_piOleInPlaceSiteEx = new COleInPlaceSiteEx((IUnknown *)this);
if (!_piOleInPlaceSiteEx)
{
Cleanup();
return FALSE;
}
_piOleInPlaceSiteEx->AddRef();
DC_END_FN();
return TRUE;
}
//
// Create the child window that directly hosts the control
//
BOOL CAxHostWnd::CreateHostWnd(HWND hwndParent, HINSTANCE hInst)
{
DC_BEGIN_FN("CreateHostWnd");
#ifndef OS_WINCE
WNDCLASSEX wndclass;
#else
WNDCLASS wndclass;
#endif
int hr = GetLastError();
#ifndef OS_WINCE
wndclass.cbSize = sizeof (wndclass);
#endif
wndclass.style = 0;
wndclass.lpfnWndProc = CAxHostWnd::StaticAxHostWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInst;
wndclass.hIcon = NULL;
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject(NULL_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = TSC_AX_HOSTWND_CLS;
#ifndef OS_WINCE
wndclass.hIconSm = NULL;
#endif
#ifndef OS_WINCE
if ((0 == RegisterClassEx(&wndclass)) &&
#else
if ((0 == RegisterClass(&wndclass)) &&
#endif
(ERROR_CLASS_ALREADY_EXISTS != GetLastError()))
{
TRC_ERR((TB,_T("RegisterClassEx failed: %d"),GetLastError()));
return FALSE;
}
RECT rc;
GetClientRect(hwndParent, &rc);
_hWnd = CreateWindow(TSC_AX_HOSTWND_CLS,
NULL,
WS_CHILD,
0,
0,
rc.right - rc.left,
rc.bottom - rc.top,
hwndParent,
NULL,
hInst,
this);
if (_hWnd)
{
// put a reference to the current object into the hwnd
// so we can access the object from the WndProc
SetWindowLongPtr(_hWnd, GWLP_USERDATA, (LONG_PTR)this);
// put the newly created hwnd into the client site objects also
TRC_ASSERT(_piOleInPlaceSiteEx,
(TB,_T("Don't create window until container is created")));
TRC_ASSERT(_pTsc && _piEventSink,
(TB,_T("Shouldn't create window until Control is instantiated")));
if (_piOleInPlaceSiteEx)
{
_piOleInPlaceSiteEx->SetHwnd(_hWnd);
}
//
// Show the control
//
hr = _piOleObject->DoVerb(OLEIVERB_PRIMARY,
NULL,
_piOleClientSite,
0,
_hWnd, &rc);
TRC_ASSERT(SUCCEEDED(hr),(TB,_T("DoVerb OLEIVERB_PRIMARY failed: %d"),hr));
if(SUCCEEDED(hr))
{
ShowWindow(_hWnd, SW_SHOWNORMAL);
return TRUE;
}
else
{
return FALSE;
}
}
else
{
TRC_ERR((TB,_T("CreateHost wnd failed")));
return FALSE;
}
DC_END_FN();
}
//
// return one of
// AXHOST_SUCCESS,
// ERR_AXHOST_DLLNOTFOUND,
// ERR_AXHOST_VERSIONMISMATCH
// ERR_AXHOST_ERROR
// so caller can display appropriate error msg
//
INT CAxHostWnd::CreateControl(IMsRdpClient** ppTscCtl)
{
DC_BEGIN_FN("CreateControl");
LPFNGETTSCCTLVER pfnDllGetTscCtlVer = NULL;
LPFNGETCLASSOBJECT pfnDllGetClassObject = NULL;
IClassFactory *piClassFactory = NULL;
IConnectionPointContainer *piConnectionPointContainer = NULL;
IConnectionPoint *piConnectionPoint = NULL;
TRC_ASSERT(ppTscCtl,(TB,_T("ppTscCtl param is null")));
if(!ppTscCtl)
{
return ERR_AXHOST_ERROR;
}
// get an interface to the control without CoCreateInstance
_hLib = LoadLibrary(TSC_CONTROL_DLL);
if (_hLib == NULL)
{
TRC_ABORT((TB, _T("LoadLibrary of the control failed")));
return ERR_AXHOST_DLLNOTFOUND;
}
//
// First do a version check to ensure ctl and shell match
//
pfnDllGetTscCtlVer = (LPFNGETTSCCTLVER)GetProcAddress(_hLib,
CE_WIDETEXT("DllGetTscCtlVer"));
if(NULL == pfnDllGetTscCtlVer)
{
TRC_ABORT((TB, _T("GetProcAddress (DllGetTscCtlVer) failed")));
return ERR_AXHOST_ERROR;
}
DWORD dwCtlVer = pfnDllGetTscCtlVer();
#ifndef OS_WINCE
DWORD dwShellVer = VER_PRODUCTVERSION_DW;
#else
DWORD dwShellVer = CE_TSC_BUILDNO;
#endif
TRC_ASSERT(dwShellVer == dwCtlVer,
(TB,_T("Control and shell versions do not match")));
if(dwShellVer != dwCtlVer)
{
return ERR_AXHOST_VERSIONMISMATCH;
}
pfnDllGetClassObject = (LPFNGETCLASSOBJECT)GetProcAddress(_hLib,
CE_WIDETEXT("DllGetClassObject"));
if (NULL == pfnDllGetClassObject)
{
TRC_ABORT((TB, _T("GetProcAddress failed")));
return ERR_AXHOST_ERROR;
}
if (FAILED(pfnDllGetClassObject(CLSID_MsRdpClient, IID_IClassFactory,
(void **)&piClassFactory)))
{
TRC_ABORT((TB, _T("pfnDllGetClassObject failed")));
return ERR_AXHOST_ERROR;
}
if (FAILED(piClassFactory->CreateInstance(NULL, IID_IMsRdpClient,
(void **)&_pTsc)))
{
piClassFactory->Release();
TRC_ERR((TB, _T("CreateInstance failed")));
return ERR_AXHOST_ERROR;
}
piClassFactory->Release();
// set up our notification event sink
if (FAILED(_pTsc->QueryInterface(IID_IConnectionPointContainer,
(void **)&piConnectionPointContainer)))
{
TRC_ABORT((TB, _T("Couldn't find IConnectionPointContainer")));
return ERR_AXHOST_ERROR;
}
if (FAILED(piConnectionPointContainer->FindConnectionPoint(
DIID_IMsTscAxEvents,
&piConnectionPoint)))
{
piConnectionPointContainer->Release();
TRC_ABORT((TB, _T("Couldn't find ConnectionPoint for Event Sink")));
return ERR_AXHOST_ERROR;
}
piConnectionPointContainer->Release();
_piEventSink = new CEventSink(_pParentWnd);
if (!_piEventSink)
{
piConnectionPoint->Release();
TRC_ABORT((TB, _T("Unable to create event sink")));
return ERR_AXHOST_ERROR;
}
_piEventSink->AddRef();
if (FAILED(piConnectionPoint->Advise((IUnknown *)_piEventSink,
&_dwConCookie)))
{
piConnectionPoint->Release();
//
// we have to release and clean up this pointer here in case of failure
// because cleanup code assumes that existence of this pointer means
// successful advise, and it tries to do the full Unadvise business in
// that case
_piEventSink->Release();
_piEventSink = NULL;
TRC_ABORT((TB, _T("Unable to advise ConnectionPoint of Event Sink")));
return ERR_AXHOST_ERROR;
}
piConnectionPoint->Release();
if ((FAILED(_pTsc->QueryInterface(IID_IOleObject, (void **)&_piOleObject))) ||
(FAILED(_pTsc->QueryInterface(IID_IOleInPlaceActiveObject,
(void **)&_piOleInPlaceActiveObject))))
{
TRC_ABORT((TB, _T("QI for IOleObject and IOleInPlaceObject failed")));
return ERR_AXHOST_ERROR;
}
if((FAILED(_pTsc->QueryInterface(IID_IOleInPlaceObject,
(void **)&_piOleInPlaceObject))))
{
TRC_ABORT((TB, _T("QI for IID_IOleInPlaceObject failed")));
return ERR_AXHOST_ERROR;
}
if (FAILED(_piOleObject->SetClientSite(_piOleClientSite)))
{
TRC_ABORT((TB, _T("Couldn't Set Client Site")));
return ERR_AXHOST_ERROR;
}
*ppTscCtl = _pTsc;
_pTsc->AddRef();
DC_END_FN();
return AXHOST_SUCCESS;
}
BOOL CAxHostWnd::Cleanup()
{
DC_BEGIN_FN("Cleanup");
if (_piEventSink)
{
TRC_ASSERT(_pTsc, (TB,_T("Event sink can't exist without tsc pointer!")));
if (_pTsc)
{
IConnectionPointContainer *piConnectionPointContainer = NULL;
IConnectionPoint *piConnectionPoint = NULL;
if (FAILED(_pTsc->QueryInterface(IID_IConnectionPointContainer,
(void **)&piConnectionPointContainer)))
{
TRC_ABORT((TB,_T("Couldn't find IConnectionPointContainer")));
}
else
{
if (FAILED(piConnectionPointContainer->FindConnectionPoint(
DIID_IMsTscAxEvents,
&piConnectionPoint)))
{
TRC_ABORT((TB,_T("Couldn't find connection point for ev sink")));
}
else
{
if (FAILED(piConnectionPoint->Unadvise(_dwConCookie)))
{
TRC_ERR((TB,_T("Unadvise connection point failed!")));
}
piConnectionPoint->Release();
}
piConnectionPointContainer->Release();
}
}
_piEventSink->Release();
_piEventSink = NULL;
}
if (_piOleInPlaceActiveObject)
_piOleInPlaceActiveObject->Release();
if (_piOleObject)
_piOleObject->Release();
if (_pTsc)
_pTsc->Release();
if (_piOleInPlaceSiteEx)
_piOleInPlaceSiteEx->Release();
if (_piOleClientSite)
_piOleClientSite->Release();
if(_piOleInPlaceObject)
_piOleInPlaceObject->Release();
if (_hWnd && IsWindow(_hWnd))
DestroyWindow(_hWnd);
_piEventSink = NULL;
_piOleInPlaceSiteEx = NULL;
_piOleClientSite = NULL;
_pTsc = NULL;
_piOleObject = NULL;
_piOleInPlaceActiveObject = NULL;
_piOleInPlaceObject = NULL;
if (_hLib)
{
LPFNCANUNLOADNOW pfnDllCanUnloadNow = (LPFNCANUNLOADNOW)
GetProcAddress(_hLib, CE_WIDETEXT("DllCanUnloadNow"));
if (pfnDllCanUnloadNow == NULL)
{
TRC_ABORT((TB,_T("GetProcAddress failed")));
FreeLibrary(_hLib);
}
else
{
if (S_OK == pfnDllCanUnloadNow())
{
FreeLibrary(_hLib);
}
else
{
TRC_ABORT((TB,_T("Library not ready for unloading @ cleanup time")));
}
}
}
_hLib = NULL;
DC_END_FN();
return TRUE;
}
HWND CAxHostWnd::GetHwnd()
{
DC_BEGIN_FN("GetHwnd");
DC_END_FN();
return _hWnd;
}
IMsRdpClient* CAxHostWnd::GetTscCtl()
{
DC_BEGIN_FN("GetTscCtl");
if (_pTsc)
{
_pTsc->AddRef();
return _pTsc;
}
DC_END_FN();
return NULL;
}
LRESULT CALLBACK CAxHostWnd::StaticAxHostWndProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
DC_BEGIN_FN("StaticAxHostWndProc");
// pull out the pointer to the container object associated with this hwnd
CAxHostWnd *piAxHst = (CAxHostWnd *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(piAxHst)
{
return piAxHst->AxHostWndProc( hwnd, uMsg, wParam, lParam);
}
else
{
return DefWindowProc (hwnd, uMsg, wParam, lParam);
}
DC_END_FN();
}
LRESULT CALLBACK CAxHostWnd::AxHostWndProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
DC_BEGIN_FN("AxHostWndProc");
//
// Reflect appropriate messages to control
//
switch (uMsg)
{
#ifndef OS_WINCE
case WM_ACTIVATEAPP:
{
_piOleInPlaceActiveObject->OnFrameWindowActivate((BOOL)wParam);
}
break;
#endif
case WM_SETFOCUS:
{
HWND hwndObj;
_piOleInPlaceActiveObject->GetWindow(&hwndObj);
SetFocus(hwndObj);
}
break;
case WM_PALETTECHANGED: // intentional fallthru
case WM_QUERYNEWPALETTE: // intentional fallthru
case WM_SYSCOLORCHANGE:
{
HWND hwndObj;
//
// Forward the message directly to the control
//
if (_piOleInPlaceActiveObject)
{
_piOleInPlaceActiveObject->GetWindow(&hwndObj);
SendMessage(hwndObj, uMsg, wParam, lParam);
}
return 1;
}
break;
case WM_SIZE:
{
int nWidth = LOWORD(lParam);
int nHeight = HIWORD(lParam);
RECT rcPos;
rcPos.bottom = nHeight;
rcPos.right = nWidth;
rcPos.left = 0;
rcPos.top = 0;
if(_piOleInPlaceObject)
_piOleInPlaceObject->SetObjectRects(&rcPos,&rcPos);
HWND hwndObj;
_piOleInPlaceActiveObject->GetWindow(&hwndObj);
SendMessage(hwndObj, WM_SIZE, wParam, lParam);
return 0;
}
break;
default:
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
break;
}
DC_END_FN();
return 0;
}