Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

599 lines
16 KiB

  1. //
  2. // axhostwnd.cpp: ActiveX control host window
  3. // (For ts activeX control)
  4. //
  5. // Copyright Microsoft Corportation 2000
  6. // (nadima)
  7. //
  8. #include "stdafx.h"
  9. #define TRC_GROUP TRC_GROUP_UI
  10. #define TRC_FILE "axhostwnd.cpp"
  11. #include <atrcapi.h>
  12. #define TSC_AX_HOSTWND_CLS TEXT("TSCAXHOST")
  13. #define TSC_CONTROL_DLL TEXT("mstscax.dll")
  14. #include "axhostwnd.h"
  15. #ifndef OS_WINCE
  16. #include "ntverp.h"
  17. #else
  18. #include "ceconfig.h"
  19. #endif
  20. CAxHostWnd::CAxHostWnd(CContainerWnd* pParentWnd) : _pParentWnd(pParentWnd)
  21. {
  22. DC_BEGIN_FN("CAxHostWnd");
  23. _hWnd = NULL;
  24. _pTsc = NULL;
  25. _cRef = 1;
  26. _hLib = NULL;
  27. _piEventSink = NULL;
  28. _piOleClientSite = NULL;
  29. _piOleInPlaceSiteEx = NULL;
  30. _piOleObject = NULL;
  31. _piOleInPlaceActiveObject = NULL;
  32. _piOleInPlaceObject = NULL;
  33. _dwConCookie = 0;
  34. TRC_ASSERT(_pParentWnd,(TB,_T("_pParentWnd not set")));
  35. DC_END_FN();
  36. }
  37. CAxHostWnd::~CAxHostWnd()
  38. {
  39. DC_BEGIN_FN("~CAxHostWnd");
  40. TRC_ASSERT(_piEventSink == NULL,(TB,_T("Exit without cleanup")));
  41. TRC_ASSERT(_piOleClientSite == NULL,(TB,_T("Exit without cleanup")));
  42. TRC_ASSERT(_piOleInPlaceSiteEx == NULL,(TB,_T("Exit without cleanup")));
  43. TRC_ASSERT(_piOleObject == NULL,(TB,_T("Exit without cleanup")));
  44. TRC_ASSERT(_piOleInPlaceActiveObject == NULL,(TB,_T("Exit without cleanup")));
  45. TRC_ASSERT(_piOleInPlaceObject == NULL,(TB,_T("Exit without cleanup")));
  46. TRC_ASSERT(_pTsc == NULL,(TB,_T("Exit without cleanup")));
  47. DC_END_FN();
  48. }
  49. STDMETHODIMP CAxHostWnd::QueryInterface( REFIID riid, void ** ppv )
  50. {
  51. DC_BEGIN_FN("QueryInterface");
  52. TRC_ASSERT(ppv != NULL,(TB,_T("ppv null")));
  53. TRC_ASSERT(_piOleClientSite != NULL,
  54. (TB,_T("QI needs IOleClientSite object")));
  55. TRC_ASSERT(_piOleInPlaceSiteEx != NULL,
  56. (TB,_T("QI needs _piOleInPlaceSiteEx object")));
  57. if (ppv)
  58. {
  59. *ppv = NULL;
  60. }
  61. else
  62. {
  63. return E_INVALIDARG;
  64. }
  65. if (IID_IUnknown == riid)
  66. *ppv = this;
  67. else if (IID_IOleClientSite == riid)
  68. *ppv = (void *)_piOleClientSite;
  69. else if (IID_IOleInPlaceSiteEx == riid)
  70. *ppv = (void *)_piOleInPlaceSiteEx;
  71. if (NULL != *ppv)
  72. {
  73. ((LPUNKNOWN)*ppv)->AddRef();
  74. return NOERROR;
  75. }
  76. DC_END_FN();
  77. return ResultFromScode(E_NOINTERFACE);
  78. }
  79. STDMETHODIMP_(ULONG) CAxHostWnd::AddRef(void)
  80. {
  81. return InterlockedIncrement(&_cRef);
  82. }
  83. STDMETHODIMP_(ULONG) CAxHostWnd::Release(void)
  84. {
  85. if (0L != InterlockedDecrement(&_cRef))
  86. {
  87. return _cRef;
  88. }
  89. delete this;
  90. return 0L;
  91. }
  92. CAxHostWnd::Init()
  93. {
  94. DC_BEGIN_FN("Init");
  95. _piOleClientSite = new COleClientSite((IUnknown *)this);
  96. if (!_piOleClientSite)
  97. {
  98. Cleanup();
  99. return FALSE;
  100. }
  101. _piOleClientSite->AddRef();
  102. _piOleInPlaceSiteEx = new COleInPlaceSiteEx((IUnknown *)this);
  103. if (!_piOleInPlaceSiteEx)
  104. {
  105. Cleanup();
  106. return FALSE;
  107. }
  108. _piOleInPlaceSiteEx->AddRef();
  109. DC_END_FN();
  110. return TRUE;
  111. }
  112. //
  113. // Create the child window that directly hosts the control
  114. //
  115. BOOL CAxHostWnd::CreateHostWnd(HWND hwndParent, HINSTANCE hInst)
  116. {
  117. DC_BEGIN_FN("CreateHostWnd");
  118. #ifndef OS_WINCE
  119. WNDCLASSEX wndclass;
  120. #else
  121. WNDCLASS wndclass;
  122. #endif
  123. int hr = GetLastError();
  124. #ifndef OS_WINCE
  125. wndclass.cbSize = sizeof (wndclass);
  126. #endif
  127. wndclass.style = 0;
  128. wndclass.lpfnWndProc = CAxHostWnd::StaticAxHostWndProc;
  129. wndclass.cbClsExtra = 0;
  130. wndclass.cbWndExtra = 0;
  131. wndclass.hInstance = hInst;
  132. wndclass.hIcon = NULL;
  133. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  134. wndclass.hbrBackground = (HBRUSH) GetStockObject(NULL_BRUSH);
  135. wndclass.lpszMenuName = NULL;
  136. wndclass.lpszClassName = TSC_AX_HOSTWND_CLS;
  137. #ifndef OS_WINCE
  138. wndclass.hIconSm = NULL;
  139. #endif
  140. #ifndef OS_WINCE
  141. if ((0 == RegisterClassEx(&wndclass)) &&
  142. #else
  143. if ((0 == RegisterClass(&wndclass)) &&
  144. #endif
  145. (ERROR_CLASS_ALREADY_EXISTS != GetLastError()))
  146. {
  147. TRC_ERR((TB,_T("RegisterClassEx failed: %d"),GetLastError()));
  148. return FALSE;
  149. }
  150. RECT rc;
  151. GetClientRect(hwndParent, &rc);
  152. _hWnd = CreateWindow(TSC_AX_HOSTWND_CLS,
  153. NULL,
  154. WS_CHILD,
  155. 0,
  156. 0,
  157. rc.right - rc.left,
  158. rc.bottom - rc.top,
  159. hwndParent,
  160. NULL,
  161. hInst,
  162. this);
  163. if (_hWnd)
  164. {
  165. // put a reference to the current object into the hwnd
  166. // so we can access the object from the WndProc
  167. SetWindowLongPtr(_hWnd, GWLP_USERDATA, (LONG_PTR)this);
  168. // put the newly created hwnd into the client site objects also
  169. TRC_ASSERT(_piOleInPlaceSiteEx,
  170. (TB,_T("Don't create window until container is created")));
  171. TRC_ASSERT(_pTsc && _piEventSink,
  172. (TB,_T("Shouldn't create window until Control is instantiated")));
  173. if (_piOleInPlaceSiteEx)
  174. {
  175. _piOleInPlaceSiteEx->SetHwnd(_hWnd);
  176. }
  177. //
  178. // Show the control
  179. //
  180. hr = _piOleObject->DoVerb(OLEIVERB_PRIMARY,
  181. NULL,
  182. _piOleClientSite,
  183. 0,
  184. _hWnd, &rc);
  185. TRC_ASSERT(SUCCEEDED(hr),(TB,_T("DoVerb OLEIVERB_PRIMARY failed: %d"),hr));
  186. if(SUCCEEDED(hr))
  187. {
  188. ShowWindow(_hWnd, SW_SHOWNORMAL);
  189. return TRUE;
  190. }
  191. else
  192. {
  193. return FALSE;
  194. }
  195. }
  196. else
  197. {
  198. TRC_ERR((TB,_T("CreateHost wnd failed")));
  199. return FALSE;
  200. }
  201. DC_END_FN();
  202. }
  203. //
  204. // return one of
  205. // AXHOST_SUCCESS,
  206. // ERR_AXHOST_DLLNOTFOUND,
  207. // ERR_AXHOST_VERSIONMISMATCH
  208. // ERR_AXHOST_ERROR
  209. // so caller can display appropriate error msg
  210. //
  211. INT CAxHostWnd::CreateControl(IMsRdpClient** ppTscCtl)
  212. {
  213. DC_BEGIN_FN("CreateControl");
  214. LPFNGETTSCCTLVER pfnDllGetTscCtlVer = NULL;
  215. LPFNGETCLASSOBJECT pfnDllGetClassObject = NULL;
  216. IClassFactory *piClassFactory = NULL;
  217. IConnectionPointContainer *piConnectionPointContainer = NULL;
  218. IConnectionPoint *piConnectionPoint = NULL;
  219. TRC_ASSERT(ppTscCtl,(TB,_T("ppTscCtl param is null")));
  220. if(!ppTscCtl)
  221. {
  222. return ERR_AXHOST_ERROR;
  223. }
  224. // get an interface to the control without CoCreateInstance
  225. _hLib = LoadLibrary(TSC_CONTROL_DLL);
  226. if (_hLib == NULL)
  227. {
  228. TRC_ABORT((TB, _T("LoadLibrary of the control failed")));
  229. return ERR_AXHOST_DLLNOTFOUND;
  230. }
  231. //
  232. // First do a version check to ensure ctl and shell match
  233. //
  234. pfnDllGetTscCtlVer = (LPFNGETTSCCTLVER)GetProcAddress(_hLib,
  235. CE_WIDETEXT("DllGetTscCtlVer"));
  236. if(NULL == pfnDllGetTscCtlVer)
  237. {
  238. TRC_ABORT((TB, _T("GetProcAddress (DllGetTscCtlVer) failed")));
  239. return ERR_AXHOST_ERROR;
  240. }
  241. DWORD dwCtlVer = pfnDllGetTscCtlVer();
  242. #ifndef OS_WINCE
  243. DWORD dwShellVer = VER_PRODUCTVERSION_DW;
  244. #else
  245. DWORD dwShellVer = CE_TSC_BUILDNO;
  246. #endif
  247. TRC_ASSERT(dwShellVer == dwCtlVer,
  248. (TB,_T("Control and shell versions do not match")));
  249. if(dwShellVer != dwCtlVer)
  250. {
  251. return ERR_AXHOST_VERSIONMISMATCH;
  252. }
  253. pfnDllGetClassObject = (LPFNGETCLASSOBJECT)GetProcAddress(_hLib,
  254. CE_WIDETEXT("DllGetClassObject"));
  255. if (NULL == pfnDllGetClassObject)
  256. {
  257. TRC_ABORT((TB, _T("GetProcAddress failed")));
  258. return ERR_AXHOST_ERROR;
  259. }
  260. if (FAILED(pfnDllGetClassObject(CLSID_MsRdpClient, IID_IClassFactory,
  261. (void **)&piClassFactory)))
  262. {
  263. TRC_ABORT((TB, _T("pfnDllGetClassObject failed")));
  264. return ERR_AXHOST_ERROR;
  265. }
  266. if (FAILED(piClassFactory->CreateInstance(NULL, IID_IMsRdpClient,
  267. (void **)&_pTsc)))
  268. {
  269. piClassFactory->Release();
  270. TRC_ERR((TB, _T("CreateInstance failed")));
  271. return ERR_AXHOST_ERROR;
  272. }
  273. piClassFactory->Release();
  274. // set up our notification event sink
  275. if (FAILED(_pTsc->QueryInterface(IID_IConnectionPointContainer,
  276. (void **)&piConnectionPointContainer)))
  277. {
  278. TRC_ABORT((TB, _T("Couldn't find IConnectionPointContainer")));
  279. return ERR_AXHOST_ERROR;
  280. }
  281. if (FAILED(piConnectionPointContainer->FindConnectionPoint(
  282. DIID_IMsTscAxEvents,
  283. &piConnectionPoint)))
  284. {
  285. piConnectionPointContainer->Release();
  286. TRC_ABORT((TB, _T("Couldn't find ConnectionPoint for Event Sink")));
  287. return ERR_AXHOST_ERROR;
  288. }
  289. piConnectionPointContainer->Release();
  290. _piEventSink = new CEventSink(_pParentWnd);
  291. if (!_piEventSink)
  292. {
  293. piConnectionPoint->Release();
  294. TRC_ABORT((TB, _T("Unable to create event sink")));
  295. return ERR_AXHOST_ERROR;
  296. }
  297. _piEventSink->AddRef();
  298. if (FAILED(piConnectionPoint->Advise((IUnknown *)_piEventSink,
  299. &_dwConCookie)))
  300. {
  301. piConnectionPoint->Release();
  302. //
  303. // we have to release and clean up this pointer here in case of failure
  304. // because cleanup code assumes that existence of this pointer means
  305. // successful advise, and it tries to do the full Unadvise business in
  306. // that case
  307. _piEventSink->Release();
  308. _piEventSink = NULL;
  309. TRC_ABORT((TB, _T("Unable to advise ConnectionPoint of Event Sink")));
  310. return ERR_AXHOST_ERROR;
  311. }
  312. piConnectionPoint->Release();
  313. if ((FAILED(_pTsc->QueryInterface(IID_IOleObject, (void **)&_piOleObject))) ||
  314. (FAILED(_pTsc->QueryInterface(IID_IOleInPlaceActiveObject,
  315. (void **)&_piOleInPlaceActiveObject))))
  316. {
  317. TRC_ABORT((TB, _T("QI for IOleObject and IOleInPlaceObject failed")));
  318. return ERR_AXHOST_ERROR;
  319. }
  320. if((FAILED(_pTsc->QueryInterface(IID_IOleInPlaceObject,
  321. (void **)&_piOleInPlaceObject))))
  322. {
  323. TRC_ABORT((TB, _T("QI for IID_IOleInPlaceObject failed")));
  324. return ERR_AXHOST_ERROR;
  325. }
  326. if (FAILED(_piOleObject->SetClientSite(_piOleClientSite)))
  327. {
  328. TRC_ABORT((TB, _T("Couldn't Set Client Site")));
  329. return ERR_AXHOST_ERROR;
  330. }
  331. *ppTscCtl = _pTsc;
  332. _pTsc->AddRef();
  333. DC_END_FN();
  334. return AXHOST_SUCCESS;
  335. }
  336. BOOL CAxHostWnd::Cleanup()
  337. {
  338. DC_BEGIN_FN("Cleanup");
  339. if (_piEventSink)
  340. {
  341. TRC_ASSERT(_pTsc, (TB,_T("Event sink can't exist without tsc pointer!")));
  342. if (_pTsc)
  343. {
  344. IConnectionPointContainer *piConnectionPointContainer = NULL;
  345. IConnectionPoint *piConnectionPoint = NULL;
  346. if (FAILED(_pTsc->QueryInterface(IID_IConnectionPointContainer,
  347. (void **)&piConnectionPointContainer)))
  348. {
  349. TRC_ABORT((TB,_T("Couldn't find IConnectionPointContainer")));
  350. }
  351. else
  352. {
  353. if (FAILED(piConnectionPointContainer->FindConnectionPoint(
  354. DIID_IMsTscAxEvents,
  355. &piConnectionPoint)))
  356. {
  357. TRC_ABORT((TB,_T("Couldn't find connection point for ev sink")));
  358. }
  359. else
  360. {
  361. if (FAILED(piConnectionPoint->Unadvise(_dwConCookie)))
  362. {
  363. TRC_ERR((TB,_T("Unadvise connection point failed!")));
  364. }
  365. piConnectionPoint->Release();
  366. }
  367. piConnectionPointContainer->Release();
  368. }
  369. }
  370. _piEventSink->Release();
  371. _piEventSink = NULL;
  372. }
  373. if (_piOleInPlaceActiveObject)
  374. _piOleInPlaceActiveObject->Release();
  375. if (_piOleObject)
  376. _piOleObject->Release();
  377. if (_pTsc)
  378. _pTsc->Release();
  379. if (_piOleInPlaceSiteEx)
  380. _piOleInPlaceSiteEx->Release();
  381. if (_piOleClientSite)
  382. _piOleClientSite->Release();
  383. if(_piOleInPlaceObject)
  384. _piOleInPlaceObject->Release();
  385. if (_hWnd && IsWindow(_hWnd))
  386. DestroyWindow(_hWnd);
  387. _piEventSink = NULL;
  388. _piOleInPlaceSiteEx = NULL;
  389. _piOleClientSite = NULL;
  390. _pTsc = NULL;
  391. _piOleObject = NULL;
  392. _piOleInPlaceActiveObject = NULL;
  393. _piOleInPlaceObject = NULL;
  394. if (_hLib)
  395. {
  396. LPFNCANUNLOADNOW pfnDllCanUnloadNow = (LPFNCANUNLOADNOW)
  397. GetProcAddress(_hLib, CE_WIDETEXT("DllCanUnloadNow"));
  398. if (pfnDllCanUnloadNow == NULL)
  399. {
  400. TRC_ABORT((TB,_T("GetProcAddress failed")));
  401. FreeLibrary(_hLib);
  402. }
  403. else
  404. {
  405. if (S_OK == pfnDllCanUnloadNow())
  406. {
  407. FreeLibrary(_hLib);
  408. }
  409. else
  410. {
  411. TRC_ABORT((TB,_T("Library not ready for unloading @ cleanup time")));
  412. }
  413. }
  414. }
  415. _hLib = NULL;
  416. DC_END_FN();
  417. return TRUE;
  418. }
  419. HWND CAxHostWnd::GetHwnd()
  420. {
  421. DC_BEGIN_FN("GetHwnd");
  422. DC_END_FN();
  423. return _hWnd;
  424. }
  425. IMsRdpClient* CAxHostWnd::GetTscCtl()
  426. {
  427. DC_BEGIN_FN("GetTscCtl");
  428. if (_pTsc)
  429. {
  430. _pTsc->AddRef();
  431. return _pTsc;
  432. }
  433. DC_END_FN();
  434. return NULL;
  435. }
  436. LRESULT CALLBACK CAxHostWnd::StaticAxHostWndProc(HWND hwnd,
  437. UINT uMsg,
  438. WPARAM wParam,
  439. LPARAM lParam)
  440. {
  441. DC_BEGIN_FN("StaticAxHostWndProc");
  442. // pull out the pointer to the container object associated with this hwnd
  443. CAxHostWnd *piAxHst = (CAxHostWnd *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  444. if(piAxHst)
  445. {
  446. return piAxHst->AxHostWndProc( hwnd, uMsg, wParam, lParam);
  447. }
  448. else
  449. {
  450. return DefWindowProc (hwnd, uMsg, wParam, lParam);
  451. }
  452. DC_END_FN();
  453. }
  454. LRESULT CALLBACK CAxHostWnd::AxHostWndProc(HWND hwnd,
  455. UINT uMsg,
  456. WPARAM wParam,
  457. LPARAM lParam)
  458. {
  459. DC_BEGIN_FN("AxHostWndProc");
  460. //
  461. // Reflect appropriate messages to control
  462. //
  463. switch (uMsg)
  464. {
  465. #ifndef OS_WINCE
  466. case WM_ACTIVATEAPP:
  467. {
  468. _piOleInPlaceActiveObject->OnFrameWindowActivate((BOOL)wParam);
  469. }
  470. break;
  471. #endif
  472. case WM_SETFOCUS:
  473. {
  474. HWND hwndObj;
  475. _piOleInPlaceActiveObject->GetWindow(&hwndObj);
  476. SetFocus(hwndObj);
  477. }
  478. break;
  479. case WM_PALETTECHANGED: // intentional fallthru
  480. case WM_QUERYNEWPALETTE: // intentional fallthru
  481. case WM_SYSCOLORCHANGE:
  482. {
  483. HWND hwndObj;
  484. //
  485. // Forward the message directly to the control
  486. //
  487. if (_piOleInPlaceActiveObject)
  488. {
  489. _piOleInPlaceActiveObject->GetWindow(&hwndObj);
  490. SendMessage(hwndObj, uMsg, wParam, lParam);
  491. }
  492. return 1;
  493. }
  494. break;
  495. case WM_SIZE:
  496. {
  497. int nWidth = LOWORD(lParam);
  498. int nHeight = HIWORD(lParam);
  499. RECT rcPos;
  500. rcPos.bottom = nHeight;
  501. rcPos.right = nWidth;
  502. rcPos.left = 0;
  503. rcPos.top = 0;
  504. if(_piOleInPlaceObject)
  505. _piOleInPlaceObject->SetObjectRects(&rcPos,&rcPos);
  506. HWND hwndObj;
  507. _piOleInPlaceActiveObject->GetWindow(&hwndObj);
  508. SendMessage(hwndObj, WM_SIZE, wParam, lParam);
  509. return 0;
  510. }
  511. break;
  512. default:
  513. {
  514. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  515. }
  516. break;
  517. }
  518. DC_END_FN();
  519. return 0;
  520. }