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.

641 lines
19 KiB

  1. /******************************************************************************
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. HelpViewerWrapper.cpp
  5. Abstract:
  6. This file contains the code to embed the Html Help Viewer as a normal ActiveX control.
  7. Revision History:
  8. Davide Massarenti (Dmassare) 10/10/99
  9. created
  10. ******************************************************************************/
  11. #include "stdafx.h"
  12. #include <shlguid.h>
  13. //
  14. // STAGING definition, until the new HTMLHELP.H gets into public.
  15. //
  16. #ifndef HH_SET_QUERYSERVICE
  17. #define HH_SET_QUERYSERVICE 0x001E // Set the Host IQueryService interface
  18. #endif
  19. ////////////////////////////////////////////////////////////////////////////////
  20. ////////////////////////////////////////////////////////////////////////////////
  21. ////////////////////////////////////////////////////////////////////////////////
  22. CPCHHelpViewerWrapper::ServiceProvider::ServiceProvider()
  23. {
  24. m_parent = NULL; // CPCHHelpCenterExternal* m_parent;
  25. m_hWnd = NULL; // HWND m_hWnd;
  26. }
  27. CPCHHelpViewerWrapper::ServiceProvider::~ServiceProvider()
  28. {
  29. Detach();
  30. }
  31. HRESULT CPCHHelpViewerWrapper::ServiceProvider::Attach( /*[in]*/ CPCHHelpCenterExternal* parent, /*[in]*/ HWND hWnd )
  32. {
  33. HRESULT hr;
  34. m_parent = parent;
  35. if(::HtmlHelpW( hWnd, NULL, HH_SET_QUERYSERVICE, (DWORD_PTR)this ))
  36. {
  37. m_hWnd = hWnd;
  38. hr = S_OK;
  39. }
  40. else
  41. {
  42. hr = E_FAIL;
  43. }
  44. return hr;
  45. }
  46. void CPCHHelpViewerWrapper::ServiceProvider::Detach()
  47. {
  48. if(m_hWnd)
  49. {
  50. (void)::HtmlHelpW( m_hWnd, NULL, HH_SET_QUERYSERVICE, (DWORD_PTR)NULL );
  51. }
  52. m_parent = NULL;
  53. m_hWnd = NULL;
  54. }
  55. ////////////////////////////////////////
  56. STDMETHODIMP CPCHHelpViewerWrapper::ServiceProvider::QueryService( REFGUID guidService, REFIID riid, void **ppv )
  57. {
  58. HRESULT hr = E_NOINTERFACE;
  59. if(m_parent)
  60. {
  61. if(InlineIsEqualGUID( guidService, SID_SInternetSecurityManager ) && m_parent->SecurityManager())
  62. {
  63. hr = m_parent->SecurityManager()->QueryInterface( riid, ppv );
  64. }
  65. else if(InlineIsEqualGUID( guidService, SID_SElementBehaviorFactory ))
  66. {
  67. if(InlineIsEqualGUID( riid, IID_IPCHHelpCenterExternal ))
  68. {
  69. hr = m_parent->QueryInterface( riid, ppv );
  70. }
  71. else if(m_parent->BehaviorFactory())
  72. {
  73. hr = m_parent->BehaviorFactory()->QueryInterface( riid, ppv );
  74. }
  75. }
  76. else if(InlineIsEqualGUID( riid, IID_IDocHostUIHandler ) && m_parent->DocHostUIHandler())
  77. {
  78. hr = m_parent->DocHostUIHandler()->QueryInterface( riid, ppv );
  79. }
  80. }
  81. return hr;
  82. }
  83. ////////////////////////////////////////////////////////////////////////////////
  84. ////////////////////////////////////////////////////////////////////////////////
  85. ////////////////////////////////////////////////////////////////////////////////
  86. MPC::CComSafeAutoCriticalSection CPCHHelpViewerWrapper::s_csec;
  87. bool CPCHHelpViewerWrapper::s_fInitialized = false;
  88. DWORD CPCHHelpViewerWrapper::s_dwLastStyle = 0;
  89. MPC::WStringList CPCHHelpViewerWrapper::s_lstAvailable;
  90. HINSTANCE CPCHHelpViewerWrapper::s_hInst = NULL;
  91. LPFNOBJECTFROMLRESULT CPCHHelpViewerWrapper::s_pfObjectFromLresult = NULL;
  92. /////////////////////////////////////////////////////////////////////////////
  93. static WCHAR l_szHCP [] = L"hcp://";
  94. static WCHAR l_szMS_ITS [] = L"ms-its:";
  95. static WCHAR l_szMSITSTORE[] = L"mk@MSITStore:";
  96. static WCHAR l_szBLANK [] = L"hcp://system/panels/blank.htm";
  97. static WCHAR l_szBLANK2 [] = L"hcp://system/panels/HHWRAPPER.htm";
  98. /////////////////////////////////////////////////////////////////////////////
  99. CPCHHelpViewerWrapper::CPCHHelpViewerWrapper()
  100. {
  101. m_bWindowOnly = TRUE; // Inherited from CComControlBase
  102. m_parent = NULL; // CPCHHelpCenterExternal* m_parent;
  103. m_ServiceProvider = NULL; // CPCHHelpViewerWrapper::ServiceProvider* m_ServiceProvider;
  104. //
  105. m_fFirstTime = true; // bool m_fFirstTime;
  106. // MPC::wstring m_szWindowStyle;
  107. m_hwndHH = NULL; // HWND m_hwndHH;
  108. //
  109. // CComPtr<IHTMLDocument2> m_spDoc;
  110. // CComPtr<IWebBrowser2> m_WB2;
  111. // CComBSTR m_bstrPendingNavigation;
  112. }
  113. CPCHHelpViewerWrapper::~CPCHHelpViewerWrapper()
  114. {
  115. }
  116. STDMETHODIMP CPCHHelpViewerWrapper::SetClientSite( IOleClientSite *pClientSite )
  117. {
  118. CComQIPtr<IServiceProvider> sp = pClientSite;
  119. MPC::Release( (IUnknown*&)m_parent );
  120. if(sp && SUCCEEDED(sp->QueryService( SID_SElementBehaviorFactory, IID_IPCHHelpCenterExternal, (void **)&m_parent )))
  121. {
  122. ;
  123. }
  124. return IOleObjectImpl<CPCHHelpViewerWrapper>::SetClientSite( pClientSite );
  125. }
  126. /////////////////////////////////////////////////////////////////////////////
  127. void CPCHHelpViewerWrapper::AcquireWindowStyle()
  128. {
  129. if(m_szWindowStyle.length() == 0)
  130. {
  131. ////////////////////////////////////////
  132. //
  133. //
  134. //
  135. s_csec.Lock();
  136. // Explicitly load MSAA so we know if it's installed
  137. if(s_hInst == NULL)
  138. {
  139. s_hInst = ::LoadLibraryW( L"OLEACC.DLL" );
  140. if(s_hInst)
  141. {
  142. s_pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)::GetProcAddress( s_hInst, "ObjectFromLresult" );
  143. }
  144. }
  145. //
  146. // If there's an old window style avaiable, reuse it!
  147. //
  148. {
  149. MPC::WStringIter it = s_lstAvailable.begin();
  150. if(it != s_lstAvailable.end())
  151. {
  152. m_szWindowStyle = *it;
  153. s_lstAvailable.erase( it );
  154. }
  155. else
  156. {
  157. WCHAR szSeq[64];
  158. swprintf( szSeq, L"HCStyle_%d", s_dwLastStyle++ );
  159. m_szWindowStyle = szSeq;
  160. }
  161. }
  162. s_csec.Unlock();
  163. //
  164. //
  165. //
  166. ////////////////////////////////////////
  167. //////////////////////////////////////////
  168. //
  169. // Initialize HH as single threaded.
  170. //
  171. if(s_fInitialized == false)
  172. {
  173. HH_GLOBAL_PROPERTY prop; ::VariantInit( &prop.var );
  174. prop.id = HH_GPROPID_SINGLETHREAD;
  175. prop.var.vt = VT_BOOL;
  176. prop.var.boolVal = VARIANT_TRUE;
  177. (void)::HtmlHelpW( NULL, NULL, HH_SET_GLOBAL_PROPERTY, (DWORD_PTR)&prop );
  178. ::VariantClear( &prop.var );
  179. s_fInitialized = true;
  180. }
  181. //
  182. //////////////////////////////////////////
  183. //////////////////////////////////////////
  184. //
  185. // Register Window Style
  186. //
  187. {
  188. USES_CONVERSION;
  189. HH_WINTYPE hhWinType;
  190. ::ZeroMemory( &hhWinType, sizeof(hhWinType) );
  191. hhWinType.idNotify = ID_NOTIFY_FROM_HH;
  192. hhWinType.pszType = (LPCTSTR)W2A(m_szWindowStyle.c_str()); // Unfortunately, HH_WINTYPE is using TCHAR instead of CHAR.
  193. hhWinType.fsValidMembers = HHWIN_PARAM_RECT |
  194. HHWIN_PARAM_PROPERTIES |
  195. HHWIN_PARAM_STYLES |
  196. HHWIN_PARAM_EXSTYLES |
  197. HHWIN_PARAM_TB_FLAGS;
  198. hhWinType.fsWinProperties = HHWIN_PROP_NODEF_STYLES |
  199. HHWIN_PROP_NODEF_EXSTYLES |
  200. HHWIN_PROP_NOTITLEBAR;
  201. hhWinType.tabpos = HHWIN_NAVTAB_LEFT;
  202. hhWinType.fNotExpanded = FALSE;
  203. hhWinType.dwStyles = WS_CHILD;
  204. hhWinType.dwExStyles = WS_EX_CONTROLPARENT;
  205. ::GetWindowRect( m_hWnd, &hhWinType.rcWindowPos );
  206. hhWinType.rcWindowPos.right -= hhWinType.rcWindowPos.left; hhWinType.rcWindowPos.left = 0;
  207. hhWinType.rcWindowPos.bottom -= hhWinType.rcWindowPos.top; hhWinType.rcWindowPos.top = 0;
  208. (void)::HtmlHelpA( m_hWnd, NULL, HH_SET_WIN_TYPE, (DWORD_PTR)&hhWinType );
  209. }
  210. //
  211. //////////////////////////////////////////
  212. }
  213. }
  214. void CPCHHelpViewerWrapper::ReleaseWindowStyle()
  215. {
  216. if(m_szWindowStyle.length())
  217. {
  218. s_csec.Lock();
  219. //
  220. // Add the style to the list of available styles.
  221. //
  222. s_lstAvailable.push_back( m_szWindowStyle );
  223. m_szWindowStyle.erase();
  224. s_csec.Unlock();
  225. }
  226. }
  227. ////////////////////////////////////////////////////////////////////////////////
  228. //BUGBUG (carled) these are defined in a private copy of winuser.h from the oleacc team.
  229. // these should be removed once this is checked in.
  230. #ifndef WMOBJ_ID
  231. #define WMOBJ_ID 0x0000
  232. #endif
  233. #ifndef WMOBJ_SAMETHREAD
  234. #define WMOBJ_SAMETHREAD 0xFFFFFFFF
  235. #endif
  236. static BOOL CALLBACK EnumChildProc( HWND hwnd,LPARAM lParam )
  237. {
  238. WCHAR buf[100];
  239. ::GetClassNameW( hwnd, buf, MAXSTRLEN(buf) );
  240. if(MPC::StrICmp( buf, L"Internet Explorer_Server" ) == 0)
  241. {
  242. *(HWND*)lParam = hwnd;
  243. return FALSE;
  244. }
  245. else
  246. {
  247. return TRUE;
  248. }
  249. }
  250. void CPCHHelpViewerWrapper::ExtractWebBrowser()
  251. {
  252. if(!m_spDoc && m_hwndHH && s_pfObjectFromLresult)
  253. {
  254. HWND hWndChild = NULL;
  255. // Get 1st document window
  256. ::EnumChildWindows( m_hwndHH, EnumChildProc, (LPARAM)&hWndChild );
  257. if(hWndChild)
  258. {
  259. LRESULT lRetVal;
  260. LRESULT ref = 0;
  261. UINT nMsg = ::RegisterWindowMessageW( L"WM_HTML_GETOBJECT" );
  262. WPARAM wParam = WMOBJ_ID;
  263. //------------------------------------------------
  264. // If the window is on our thread, optimize the
  265. // marshalling/unmarshalling.
  266. //
  267. // However, the proxy support in IE is broken, so let's fake as if we are in the same thread.
  268. //
  269. //------------------------------------------------
  270. /*if(::GetWindowThreadProcessId( hWndChild, NULL ) == ::GetCurrentThreadId())*/ wParam |= WMOBJ_SAMETHREAD;
  271. lRetVal = ::SendMessageTimeout( hWndChild, nMsg, wParam, 0L, SMTO_ABORTIFHUNG, 10000, (PDWORD_PTR)&ref );
  272. if(lRetVal)
  273. {
  274. if(SUCCEEDED(s_pfObjectFromLresult( ref, IID_IHTMLDocument2, wParam, (void**)&m_spDoc )))
  275. {
  276. CComQIPtr<IServiceProvider> sp = m_spDoc;
  277. if(sp)
  278. {
  279. (void)sp->QueryService( IID_IWebBrowserApp, IID_IWebBrowser2, (void**)&m_WB2 );
  280. }
  281. }
  282. }
  283. }
  284. }
  285. }
  286. /////////////////////////////////////////////////////////////////////////////
  287. STDMETHODIMP CPCHHelpViewerWrapper::get_WebBrowser( /*[out,retval]*/ IUnknown* *pVal )
  288. {
  289. return MPC::CopyTo( (IWebBrowser2*)m_WB2, pVal );
  290. }
  291. STDMETHODIMP CPCHHelpViewerWrapper::Navigate( /*[in]*/ BSTR bstrURL )
  292. {
  293. if(m_fFirstTime)
  294. {
  295. m_bstrPendingNavigation = bstrURL;
  296. }
  297. else
  298. {
  299. if(m_hWnd && m_parent)
  300. {
  301. AcquireWindowStyle();
  302. InternalDisplayTopic( bstrURL );
  303. }
  304. }
  305. return S_OK;
  306. }
  307. STDMETHODIMP CPCHHelpViewerWrapper::Print()
  308. {
  309. __HCP_FUNC_ENTRY( "CPCHHelpViewerWrapper::Print" );
  310. HRESULT hr;
  311. if(m_WB2)
  312. {
  313. (void)m_WB2->ExecWB( OLECMDID_PRINT, OLECMDEXECOPT_DODEFAULT, NULL, NULL );
  314. }
  315. hr = S_OK;
  316. __HCP_FUNC_EXIT(hr);
  317. }
  318. ////////////////////////////////////////////////////////////////////////////////
  319. void CPCHHelpViewerWrapper::InternalDisplayTopic( /*[in]*/ LPCWSTR szURL )
  320. {
  321. if(szURL)
  322. {
  323. MPC::wstring strURL;
  324. //
  325. // If the protocol begins with HCP:// and it for an MS-ITS: domain, remove HCP://
  326. //
  327. if(!_wcsnicmp( szURL, l_szHCP, MAXSTRLEN( l_szHCP ) ))
  328. {
  329. LPCWSTR szURL2 = &szURL[ MAXSTRLEN( l_szHCP ) ];
  330. if(!_wcsnicmp( szURL2, l_szMS_ITS , MAXSTRLEN( l_szMS_ITS ) ) ||
  331. !_wcsnicmp( szURL2, l_szMSITSTORE, MAXSTRLEN( l_szMSITSTORE ) ) )
  332. {
  333. szURL = szURL2;
  334. }
  335. }
  336. strURL = szURL;
  337. strURL += L">";
  338. strURL += m_szWindowStyle;
  339. m_hwndHH = ::HtmlHelpW( m_hWnd, strURL.c_str(), HH_DISPLAY_TOPIC, NULL );
  340. }
  341. }
  342. ////////////////////////////////////////////////////////////////////////////////
  343. BOOL CPCHHelpViewerWrapper::ProcessWindowMessage( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID )
  344. {
  345. lResult = 0;
  346. switch(uMsg)
  347. {
  348. case WM_CREATE:
  349. {
  350. m_fFirstTime = true;
  351. AcquireWindowStyle();
  352. if(SUCCEEDED(MPC::CreateInstance( &m_ServiceProvider )))
  353. {
  354. (void)m_ServiceProvider->Attach( m_parent, m_hWnd );
  355. }
  356. InternalDisplayTopic( l_szBLANK ); // Load a blank page....
  357. }
  358. return TRUE;
  359. case WM_DESTROY:
  360. {
  361. if(m_parent) m_parent->SetHelpViewer( NULL );
  362. if(m_ServiceProvider)
  363. {
  364. m_ServiceProvider->Detach();
  365. MPC::Release( (IUnknown*&)m_ServiceProvider );
  366. }
  367. if(m_hwndHH)
  368. {
  369. ::SendMessage( m_hwndHH, WM_CLOSE, 0, 0 );
  370. m_hwndHH = NULL;
  371. }
  372. ReleaseWindowStyle();
  373. }
  374. return TRUE;
  375. case WM_ERASEBKGND:
  376. lResult = 1;
  377. return TRUE;
  378. case WM_SIZE:
  379. {
  380. if(m_hwndHH)
  381. {
  382. int nWidth = LOWORD(lParam); // width of client area
  383. int nHeight = HIWORD(lParam); // height of client area
  384. ::MoveWindow( m_hwndHH, 0, 0, nWidth, nHeight, TRUE );
  385. }
  386. }
  387. return TRUE;
  388. //// case WM_PAINT:
  389. //// {
  390. //// static bool fFirst = true;
  391. ////
  392. //// // if(fFirst)
  393. //// {
  394. //// fFirst = false;
  395. ////
  396. //// PAINTSTRUCT ps;
  397. ////
  398. //// HDC hdc = ::BeginPaint( m_hWnd, &ps );
  399. //// if(hdc)
  400. //// {
  401. //// RECT rc;
  402. ////
  403. //// rc.left = 20;
  404. //// rc.top = 20;
  405. //// rc.right = 200;
  406. //// rc.bottom = 200;
  407. ////
  408. //// ::FillRect( hdc, &rc, (HBRUSH)(COLOR_WINDOWTEXT+1) );
  409. //// }
  410. //// ::EndPaint( m_hWnd, &ps );
  411. //// }
  412. //// }
  413. //// return TRUE;
  414. case WM_NOTIFY:
  415. {
  416. LPNMHDR pnmh = (LPNMHDR)lParam;
  417. if(pnmh->idFrom == ID_NOTIFY_FROM_HH && pnmh->code == HHN_NAVCOMPLETE)
  418. {
  419. HHN_NOTIFY* notification = (HHN_NOTIFY*)pnmh;
  420. if(notification->pszUrl)
  421. {
  422. if(m_fFirstTime)
  423. {
  424. m_fFirstTime = false;
  425. ExtractWebBrowser();
  426. if(m_parent)
  427. {
  428. CPCHHelpSession* hs = m_parent->HelpSession();
  429. m_parent->SetHelpViewer( this );
  430. if(hs) hs->IgnoreUrl( l_szBLANK2 );
  431. }
  432. InternalDisplayTopic( l_szBLANK2 );
  433. }
  434. else
  435. {
  436. if(m_bstrPendingNavigation)
  437. {
  438. InternalDisplayTopic( m_bstrPendingNavigation ); m_bstrPendingNavigation.Empty();
  439. }
  440. }
  441. }
  442. return TRUE;
  443. }
  444. }
  445. break;
  446. }
  447. return CComControl<CPCHHelpViewerWrapper>::ProcessWindowMessage( hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID );
  448. }
  449. /////////////////////////////////////////////////////////////////////////////
  450. //////////////////////////////////////////////////////////
  451. //
  452. // Private APIs shared with HTMLHelp.
  453. //
  454. #define HH_PRETRANSLATEMESSAGE2 0x0100 // Fix for Millenium pretranslate problem. Bug 7921
  455. BOOL CPCHHelpViewerWrapper::PreTranslateAccelerator( LPMSG pMsg, HRESULT& hRet )
  456. {
  457. hRet = S_FALSE;
  458. if(m_hwndHH)
  459. {
  460. // (weizhao) Added the following code to fix the problem with switching
  461. // panels using Ctrl-Tab and F6. HtmlHelp control's handling of these
  462. // messages is not consistent with Mars or Browser control. The following
  463. // fixes some of the inconsistencies.
  464. // check if self or any offspring window has focus
  465. for (HWND hwnd = ::GetFocus(); hwnd && hwnd != m_hwndHH; hwnd = ::GetParent(hwnd)) ;
  466. BOOL hasFocus = (hwnd == m_hwndHH);
  467. // identify Ctrl-Tab and F6 keystrokes
  468. BOOL isKeydown = (pMsg && (pMsg->message == WM_KEYDOWN));
  469. BOOL isTab = (isKeydown && (pMsg->wParam == VK_TAB));
  470. BOOL isCtrlTab = (isTab && (::GetKeyState( VK_CONTROL ) & 0x8000));
  471. BOOL isF6 = (isKeydown && (pMsg->wParam == VK_F6));
  472. // map F6 and Ctrl-TAB from external windows into TAB for HtmlHelp to handle
  473. // so it can receive focus
  474. if (!hasFocus && isF6) pMsg->wParam = VK_TAB;
  475. // fake control status
  476. BYTE bState[256];
  477. if (!hasFocus && isCtrlTab)
  478. {
  479. ::GetKeyboardState(bState);
  480. bState[VK_CONTROL] &= 0x7F;
  481. ::SetKeyboardState(bState);
  482. }
  483. // pass the message to HtmlHelp for processing
  484. if(::HtmlHelp( m_hwndHH, NULL, HH_PRETRANSLATEMESSAGE2, (DWORD_PTR)pMsg ))
  485. {
  486. hRet = S_OK;
  487. }
  488. // if it should accept focus, give it another chance (seems to have
  489. // problem accepting focus the first time after a navigate)
  490. if (!hasFocus && (isTab || isF6) && hRet != S_OK)
  491. {
  492. if(::HtmlHelp( m_hwndHH, NULL, HH_PRETRANSLATEMESSAGE2, (DWORD_PTR)pMsg ))
  493. {
  494. hRet = S_OK;
  495. }
  496. }
  497. // restore control status
  498. if (!hasFocus && isCtrlTab)
  499. {
  500. bState[VK_CONTROL] |= 0x80;
  501. ::SetKeyboardState(bState);
  502. }
  503. // if the message is Ctrl-Tab and F6 and the focus is leaving,
  504. // relegate the processing to other windows by setting processed to false
  505. if (hasFocus && (isCtrlTab || isF6))
  506. {
  507. hRet = S_FALSE;
  508. }
  509. }
  510. return TRUE;
  511. }