1011 lines
31 KiB
C++
1011 lines
31 KiB
C++
|
// Copyright (C) 1996 Microsoft Corporation. All rights reserved.
|
||
|
|
||
|
#include "header.h"
|
||
|
#include "autocont.h"
|
||
|
#include <exdispid.h>
|
||
|
#include <exdisp.h>
|
||
|
#include "resource.h"
|
||
|
#include "system.h"
|
||
|
|
||
|
#include "highlite.h"
|
||
|
// make Don's stuff work
|
||
|
#ifdef HHCTRL
|
||
|
#include "parserhh.h"
|
||
|
#else
|
||
|
#include "parser.h"
|
||
|
#endif
|
||
|
#include "collect.h"
|
||
|
#include "hhtypes.h"
|
||
|
//#include "toc.h"
|
||
|
|
||
|
#define NDEF_AUTOMATIONOBJECTINFO
|
||
|
#include "secwin.h"
|
||
|
|
||
|
#include "hhfinder.h"
|
||
|
|
||
|
// from IE4 version of exdispid.h
|
||
|
//
|
||
|
#define DISPID_DOCUMENTCOMPLETE 259 // new document goes ReadyState_Complete
|
||
|
#define DISPID_BEFORENAVIGATE2 250 // hyperlink clicked on
|
||
|
#define DISPID_NAVIGATECOMPLETE2 252 // UIActivate new document
|
||
|
|
||
|
#include "wwheel.h"
|
||
|
|
||
|
#ifndef DISPID_DOCUMENTCOMPLETE
|
||
|
#define DISPID_DOCUMENTCOMPLETE 259 // new document goes ReadyState_Complete
|
||
|
#endif
|
||
|
|
||
|
CAutomateContent::CAutomateContent(CContainer * pOuter) : CUnknownObject(pOuter)
|
||
|
{
|
||
|
m_pOuter = pOuter;
|
||
|
m_cRef = 0;
|
||
|
m_fLoadedTypeInfo = FALSE;
|
||
|
m_bFirstTime = TRUE;
|
||
|
// m_pPrintHook = NULL;
|
||
|
}
|
||
|
|
||
|
CAutomateContent::~CAutomateContent()
|
||
|
{
|
||
|
// if (m_pPrintHook != NULL)
|
||
|
// delete m_pPrintHook;
|
||
|
}
|
||
|
|
||
|
// aggregating IUnknown methods
|
||
|
|
||
|
STDMETHODIMP CAutomateContent::QueryInterface(REFIID riid, LPVOID * ppv)
|
||
|
{
|
||
|
*ppv = 0;
|
||
|
|
||
|
if (m_pOuter)
|
||
|
return m_pOuter->QueryInterface(riid,ppv);
|
||
|
|
||
|
if (riid == IID_IUnknown || riid == IID_IDispatch)
|
||
|
{
|
||
|
*ppv = (LPVOID)(IDispatch*)this;
|
||
|
AddRef();
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
return E_NOINTERFACE;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CAutomateContent::AddRef(void)
|
||
|
{
|
||
|
m_cRef++;
|
||
|
|
||
|
if (m_pOuter)
|
||
|
m_pOuter->AddRef();
|
||
|
|
||
|
return m_cRef;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP_(ULONG) CAutomateContent::Release(void)
|
||
|
{
|
||
|
ULONG c = --m_cRef;
|
||
|
|
||
|
if (m_pOuter)
|
||
|
m_pOuter->Release();
|
||
|
|
||
|
if (c <= 0)
|
||
|
delete this;
|
||
|
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
// wrapping IDispatch methods
|
||
|
|
||
|
STDMETHODIMP CAutomateContent::GetTypeInfoCount(UINT* pui)
|
||
|
{
|
||
|
// arg checking
|
||
|
|
||
|
if (!pui)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
// we support GetTypeInfo, so we need to return the count here.
|
||
|
|
||
|
*pui = 1;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CAutomateContent::GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo **ppTypeInfoOut)
|
||
|
{
|
||
|
// arg checking
|
||
|
|
||
|
if (itinfo != 0)
|
||
|
return DISP_E_BADINDEX;
|
||
|
|
||
|
if (!ppTypeInfoOut)
|
||
|
return E_POINTER;
|
||
|
|
||
|
*ppTypeInfoOut = NULL;
|
||
|
|
||
|
return E_NOTIMPL;
|
||
|
|
||
|
#if 0
|
||
|
// ppTypeInfo will point to our global holder for this particular
|
||
|
// type info. if it's null, then we have to load it up. if it's not
|
||
|
// NULL, then it's already loaded, and we're happy.
|
||
|
// crit sect this entire nightmare so we're okay with multiple
|
||
|
// threads trying to use this object.
|
||
|
|
||
|
ITypeInfo** ppTypeInfo = PPTYPEINFOOFOBJECT(m_ObjectType);
|
||
|
HRESULT hr = E_INVALIDARG;;
|
||
|
|
||
|
if (*ppTypeInfo == NULL) {
|
||
|
|
||
|
ITypeInfo *pTypeInfoTmp;
|
||
|
HREFTYPE hrefType;
|
||
|
|
||
|
// we don't have the type info around, so go load the sucker.
|
||
|
|
||
|
ITypeLib *pTypeLib;
|
||
|
hr = LoadRegTypeLib(*g_pLibid, (USHORT) VERSIONOFOBJECT(m_ObjectType), 0,
|
||
|
LANG_NEUTRAL, &pTypeLib);
|
||
|
|
||
|
// if, for some reason, we failed to load the type library this
|
||
|
// way, we're going to try and load the type library directly out of
|
||
|
// our resources. this has the advantage of going and re-setting all
|
||
|
// the registry information again for us.
|
||
|
|
||
|
if (FAILED(hr)) {
|
||
|
char szDllPath[MAX_PATH];
|
||
|
DWORD dwPathLen = GetModuleFileName(_Module.GetModuleInstance(), szDllPath, MAX_PATH);
|
||
|
if (!dwPathLen) {
|
||
|
hr = E_FAIL;
|
||
|
goto CleanUp;
|
||
|
}
|
||
|
|
||
|
CWStr cwz(szDllPath);
|
||
|
hr = LoadTypeLib(cwz, &pTypeLib);
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// we've got the Type Library now, so get the type info for the interface
|
||
|
// we're interested in.
|
||
|
|
||
|
hr = pTypeLib->GetTypeInfoOfGuid((REFIID)INTERFACEOFOBJECT(m_ObjectType), &pTypeInfoTmp);
|
||
|
pTypeLib->Release();
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
|
||
|
// the following couple of lines of code are to dereference the dual
|
||
|
// interface stuff and take us right to the dispatch portion of the
|
||
|
// interfaces.
|
||
|
//
|
||
|
hr = pTypeInfoTmp->GetRefTypeOfImplType(0xffffffff, &hrefType);
|
||
|
if (FAILED(hr)) {
|
||
|
pTypeInfoTmp->Release();
|
||
|
goto CleanUp;
|
||
|
}
|
||
|
|
||
|
hr = pTypeInfoTmp->GetRefTypeInfo(hrefType, ppTypeInfo);
|
||
|
pTypeInfoTmp->Release();
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
|
||
|
// add an extra reference to this object. if it ever becomes zero, then
|
||
|
// we need to release it ourselves. crit sect this since more than
|
||
|
// one thread can party on this object.
|
||
|
//
|
||
|
CTYPEINFOOFOBJECT(m_ObjectType)++;
|
||
|
m_fLoadedTypeInfo = TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// we still have to go and addref the Type info object, however, so that
|
||
|
// the people using it can release it.
|
||
|
//
|
||
|
(*ppTypeInfo)->AddRef();
|
||
|
*ppTypeInfoOut = *ppTypeInfo;
|
||
|
hr = S_OK;
|
||
|
|
||
|
CleanUp:
|
||
|
return hr;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CAutomateContent::GetIDsOfNames(REFIID riid, OLECHAR **rgszNames, UINT cNames, LCID lcid, DISPID *rgdispid)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
ITypeInfo *pTypeInfo;
|
||
|
|
||
|
if (!DO_GUIDS_MATCH(riid, IID_NULL))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
// get the type info for this dude!
|
||
|
|
||
|
hr = GetTypeInfo(0, lcid, &pTypeInfo);
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
|
||
|
// use the standard provided routines to do all the work for us.
|
||
|
|
||
|
hr = pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
|
||
|
pTypeInfo->Release();
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// I don't know if this implementation of IDispatch::Invoke() is correct or not,
|
||
|
// but I haven't found anyone or anything that can tell me otherwise.
|
||
|
|
||
|
STDMETHODIMP CAutomateContent::Invoke(DISPID dispid, REFIID riid, LCID lcid,
|
||
|
WORD wFlags, DISPPARAMS *pdispparams, VARIANT *pvarResult,
|
||
|
EXCEPINFO *pexcepinfo, UINT *puArgErr)
|
||
|
{
|
||
|
char szURL[MAX_URL];
|
||
|
char szTFN[MAX_URL];
|
||
|
char szHeaders[MAX_URL];
|
||
|
UINT uArgErr;
|
||
|
if( !puArgErr )
|
||
|
puArgErr = &uArgErr;
|
||
|
|
||
|
// riid should always be IID_NULL.
|
||
|
|
||
|
if (!DO_GUIDS_MATCH(riid, IID_NULL))
|
||
|
return DISP_E_UNKNOWNINTERFACE;
|
||
|
|
||
|
// We only have to handle methods (no properties).
|
||
|
|
||
|
if (!(wFlags & DISPATCH_METHOD))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
HRESULT hr;
|
||
|
VARIANTARG varg;
|
||
|
|
||
|
// Initialize the variants.
|
||
|
|
||
|
VariantInit(&varg);
|
||
|
|
||
|
#ifdef EXCEPTIONS
|
||
|
|
||
|
21-Sep-1997 [ralphw] Nothing in our code throws an exception, and removing
|
||
|
exception handling cuts down on C runtime usage.
|
||
|
|
||
|
try
|
||
|
{
|
||
|
#endif
|
||
|
|
||
|
// The dispid determines which event has been fired.
|
||
|
|
||
|
switch (dispid)
|
||
|
{
|
||
|
|
||
|
// case DISPID_FRAMEBEFORENAVIGATE:
|
||
|
// case DISPID_FRAMENAVIGATECOMPLETE:
|
||
|
// case DISPID_FRAMENEWWINDOW:
|
||
|
// case DISPID_NEWWINDOW:
|
||
|
|
||
|
|
||
|
case DISPID_COMMANDSTATECHANGE: {
|
||
|
OnCommandStateChange(
|
||
|
(long) pdispparams->rgvarg[1].lVal, // VT_I4 == long
|
||
|
(BOOL) pdispparams->rgvarg[0].boolVal ); // VT_BOOL == BOOL
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
// 31-May-1997 [ralphw] We don't use these
|
||
|
|
||
|
case DISPID_PROGRESSCHANGE: {
|
||
|
OnProgressChange(
|
||
|
(long) pdispparams->rgvarg[1].lVal, // VT_I4 == long
|
||
|
(long) pdispparams->rgvarg[0].lVal ); // VT_I4 == long
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case DISPID_PROPERTYCHANGE: {
|
||
|
CStr strProperty(pdispparams->rgvarg[0].bstrVal);
|
||
|
OnPropertyChange(
|
||
|
(LPCTSTR) strProperty ); // VT_BSTR == LPCTSTR
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case DISPID_QUIT: { // also disabled in web.cpp
|
||
|
OnQuit(
|
||
|
(BOOL*) pdispparams->rgvarg[0].pboolVal ); // VT_BYREF|VT_BOOL == BOOL*
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case DISPID_STATUSTEXTCHANGE: {
|
||
|
CStr strText(pdispparams->rgvarg[0].bstrVal);
|
||
|
OnStatusTextChange(
|
||
|
(LPCTSTR) strText ); // VT_BSTR == LPCTSTR
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case DISPID_DOWNLOADCOMPLETE: // DownloadComplete
|
||
|
OnDownloadComplete();
|
||
|
break;
|
||
|
|
||
|
case DISPID_DOWNLOADBEGIN: // DownloadBegin
|
||
|
OnDownloadBegin();
|
||
|
break;
|
||
|
#endif
|
||
|
case DISPID_BEFORENAVIGATE2: // ie4 version.
|
||
|
WideCharToMultiByte(CP_ACP, 0, pdispparams->rgvarg[5].pvarVal->bstrVal, -1, szURL, sizeof(szURL), NULL, NULL);
|
||
|
|
||
|
// 27-Sep-1997 [ralphw] IE 4 will send us a script command, followed
|
||
|
// by a 1 then the current URL. We don't care about the current URL
|
||
|
// in this case, so we nuke it.
|
||
|
{
|
||
|
PSTR pszCurUrl = StrChr(szURL, 1);
|
||
|
if (pszCurUrl)
|
||
|
*pszCurUrl = '\0';
|
||
|
}
|
||
|
szTFN[0] = 0;
|
||
|
if( pdispparams->rgvarg[3].pvarVal->bstrVal )
|
||
|
WideCharToMultiByte(CP_ACP, 0, pdispparams->rgvarg[3].pvarVal->bstrVal, -1, szTFN, sizeof(szTFN), NULL, NULL);
|
||
|
szHeaders[0] = 0;
|
||
|
if( pdispparams->rgvarg[1].pvarVal->bstrVal )
|
||
|
WideCharToMultiByte(CP_ACP, 0, pdispparams->rgvarg[1].pvarVal->bstrVal, -1, szHeaders, sizeof(szHeaders), NULL, NULL);
|
||
|
OnBeforeNavigate(szURL, (long)pdispparams->rgvarg[4].pvarVal->lVal, szTFN,
|
||
|
pdispparams->rgvarg[2].pvarVal, szHeaders, (BOOL*)pdispparams->rgvarg[0].pboolVal );
|
||
|
break;
|
||
|
|
||
|
case DISPID_BEFORENAVIGATE: // ie3 version.
|
||
|
WideCharToMultiByte(CP_ACP, 0, pdispparams->rgvarg[5].bstrVal, -1, szURL, sizeof(szURL), NULL, NULL);
|
||
|
WideCharToMultiByte(CP_ACP, 0, pdispparams->rgvarg[3].bstrVal, -1, szTFN, sizeof(szTFN), NULL, NULL);
|
||
|
WideCharToMultiByte(CP_ACP, 0, pdispparams->rgvarg[1].bstrVal, -1, szHeaders, sizeof(szHeaders), NULL, NULL);
|
||
|
OnBeforeNavigate(szURL, pdispparams->rgvarg[4].lVal, szTFN, pdispparams->rgvarg[2].pvarVal,
|
||
|
szHeaders, (BOOL*)pdispparams->rgvarg[0].pboolVal);
|
||
|
break;
|
||
|
|
||
|
case DISPID_NAVIGATECOMPLETE2: // ie4 version.
|
||
|
if(g_hsemNavigate)
|
||
|
ReleaseSemaphore(g_hsemNavigate, 1, NULL); // signal our navigation semaphore
|
||
|
|
||
|
WideCharToMultiByte(CP_ACP, 0, pdispparams->rgvarg[0].pvarVal->bstrVal, -1, szURL, sizeof(szURL), NULL, NULL);
|
||
|
OnNavigateComplete(szURL);
|
||
|
break;
|
||
|
|
||
|
case DISPID_NAVIGATECOMPLETE: // ie3 version.
|
||
|
if(g_hsemNavigate)
|
||
|
ReleaseSemaphore(g_hsemNavigate, 1, NULL); // signal our navigation semaphore
|
||
|
|
||
|
WideCharToMultiByte(CP_ACP, 0, pdispparams->rgvarg[0].bstrVal, -1, szURL, sizeof(szURL), NULL, NULL);
|
||
|
OnNavigateComplete(szURL);
|
||
|
break;
|
||
|
|
||
|
case DISPID_DOCUMENTCOMPLETE: // DocumentComplete
|
||
|
OnDocumentComplete();
|
||
|
break;
|
||
|
|
||
|
case DISPID_TITLECHANGE:
|
||
|
{
|
||
|
hr = DispGetParam(pdispparams, 0, VT_BSTR, &varg, puArgErr);
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
|
||
|
CStr strURL(V_BSTR(&varg));
|
||
|
OnTitleChange((PCSTR)strURL);
|
||
|
VariantClear(&varg);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
#ifdef EXCEPTIONS
|
||
|
}
|
||
|
catch (...)
|
||
|
{
|
||
|
if (pexcepinfo != NULL)
|
||
|
{
|
||
|
// Fill in the exception struct.
|
||
|
// The struct should be filled in with more useful information than
|
||
|
// is found here.
|
||
|
pexcepinfo->wCode = 1001;
|
||
|
pexcepinfo->wReserved = 0;
|
||
|
pexcepinfo->bstrSource = L"";
|
||
|
pexcepinfo->bstrDescription = NULL;
|
||
|
pexcepinfo->bstrHelpFile = NULL;
|
||
|
pexcepinfo->dwHelpContext = 0;
|
||
|
pexcepinfo->pvReserved = NULL;
|
||
|
pexcepinfo->pfnDeferredFillIn = NULL;
|
||
|
pexcepinfo->scode = 0;
|
||
|
}
|
||
|
|
||
|
return DISP_E_EXCEPTION;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return S_OK;
|
||
|
|
||
|
#if 0
|
||
|
HRESULT hr;
|
||
|
ITypeInfo *pTypeInfo;
|
||
|
|
||
|
if (!DO_GUIDS_MATCH(riid, IID_NULL))
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
// get our typeinfo first!
|
||
|
|
||
|
hr = GetTypeInfo(0, lcid, &pTypeInfo);
|
||
|
if (FAILED(hr))
|
||
|
return hr;
|
||
|
|
||
|
// Clear exceptions
|
||
|
|
||
|
SetErrorInfo(0, NULL);
|
||
|
|
||
|
// This is exactly what DispInvoke does--so skip the overhead.
|
||
|
|
||
|
hr = pTypeInfo->Invoke(m_pvInterface, dispid, wFlags,
|
||
|
pdispparams, pvarResult,
|
||
|
pexcepinfo, puArgErr);
|
||
|
pTypeInfo->Release();
|
||
|
return hr;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// actual useful code, as it were...
|
||
|
|
||
|
void CAutomateContent::LookupKeyword(LPCSTR pszKeyword)
|
||
|
{
|
||
|
// gpCOurPackage->LookupKeyword(pszKeyword);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// WebBrowser Event Notification interface.
|
||
|
//
|
||
|
// More actual usefull code, thank god we have Craig!
|
||
|
//
|
||
|
// These are the WebBrowserEvents (I call them notifications ?)
|
||
|
|
||
|
void CAutomateContent::OnCommandStateChange(long Command, BOOL Enable)
|
||
|
{
|
||
|
DBWIN("OnCommandStateChange Event Called.");
|
||
|
HMENU hMenu;
|
||
|
WPARAM btn_index;
|
||
|
TBBUTTON tbbtn;
|
||
|
|
||
|
CHHWinType* phh = FindHHWindowIndex(m_pOuter);
|
||
|
if (!phh || !phh->hwndToolBar || !phh->hwndHelp)
|
||
|
return;
|
||
|
|
||
|
hMenu = GetMenu(phh->hwndHelp);
|
||
|
btn_index = SendMessage(phh->hwndToolBar, TB_COMMANDTOINDEX, IDTB_OPTIONS, 0L);
|
||
|
if( btn_index == (WPARAM) -1 )
|
||
|
return;
|
||
|
SendMessage(phh->hwndToolBar, TB_GETBUTTON, btn_index, (LPARAM) (LPTBBUTTON) &tbbtn);
|
||
|
|
||
|
switch (Command)
|
||
|
{
|
||
|
case 1:
|
||
|
if ( phh->fsToolBarFlags & HHWIN_BUTTON_FORWARD )
|
||
|
SendMessage(phh->hwndToolBar, TB_ENABLEBUTTON, IDTB_FORWARD, Enable);
|
||
|
if ( hMenu )
|
||
|
EnableMenuItem(hMenu, IDTB_FORWARD, (MF_BYCOMMAND | (Enable?MF_ENABLED:MF_GRAYED)));
|
||
|
if ( tbbtn.dwData )
|
||
|
EnableMenuItem((HMENU)tbbtn.dwData, IDTB_FORWARD, (MF_BYCOMMAND | (Enable?MF_ENABLED:MF_GRAYED)));
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
if ( phh->fsToolBarFlags & HHWIN_BUTTON_BACK )
|
||
|
SendMessage(phh->hwndToolBar, TB_ENABLEBUTTON, IDTB_BACK, Enable);
|
||
|
if ( hMenu )
|
||
|
EnableMenuItem(hMenu, IDTB_BACK, (MF_BYCOMMAND | (Enable?MF_ENABLED:MF_GRAYED)));
|
||
|
if ( tbbtn.dwData )
|
||
|
EnableMenuItem((HMENU)tbbtn.dwData, IDTB_BACK, (MF_BYCOMMAND | (Enable?MF_ENABLED:MF_GRAYED)));
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CAutomateContent::OnDownloadBegin()
|
||
|
{
|
||
|
DBWIN("OnDownloadBegin Event Called.");
|
||
|
|
||
|
// if (m_pPrintHook != NULL)
|
||
|
// m_pPrintHook->OnDownloadBegin();
|
||
|
|
||
|
// gpCOurPackage->m_bAllowStop = TRUE; // Stopping allowed during download.
|
||
|
// gpCOurPackage->m_EnableRefresh = FALSE; // Refresh not allowed during download.
|
||
|
}
|
||
|
|
||
|
void CAutomateContent::OnDownloadComplete()
|
||
|
{
|
||
|
DBWIN("OnDownloadComplete Event Called.");
|
||
|
|
||
|
// if (m_pPrintHook != NULL)
|
||
|
// m_pPrintHook->OnDownloadComplete();
|
||
|
|
||
|
// gpCOurPackage->m_bAllowStop = FALSE; // Disable stop after download complete.
|
||
|
// gpCOurPackage->m_EnableRefresh = TRUE; // Enable refresh.
|
||
|
|
||
|
}
|
||
|
|
||
|
void CAutomateContent::OnBeforeNavigate(LPCTSTR pszURL, long Flags,
|
||
|
LPCTSTR TargetFrameName, VARIANT* pPostData, LPCTSTR Headers, BOOL* pfCancel)
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
char sz[MAX_URL];
|
||
|
wsprintf(sz, "OnBeforeNavigate Event Called: %s", pszURL);
|
||
|
DBWIN(sz);
|
||
|
#endif
|
||
|
|
||
|
CStr PathName;
|
||
|
BOOL bInitNewTitle = FALSE;
|
||
|
BOOL bNewNavigate = FALSE;
|
||
|
WPARAM wParam = 0;
|
||
|
LPARAM lParam = 0;
|
||
|
|
||
|
UINT uiURLType = GetURLType( pszURL );
|
||
|
|
||
|
// new jump pointer
|
||
|
LPTSTR pszJumpURL = (LPTSTR) pszURL;
|
||
|
|
||
|
// default cancel to false
|
||
|
*pfCancel = FALSE;
|
||
|
|
||
|
// if we get a javascript then get the current URL so we
|
||
|
// can do some CD prompting to ensure the current topic is available
|
||
|
// to avoid multiple prompts for the topic via the finder
|
||
|
BOOL bJump = TRUE;
|
||
|
CStr szCurrentURL;
|
||
|
if( uiURLType == HH_URL_JAVASCRIPT ) {
|
||
|
bJump = FALSE;
|
||
|
//Don't use --> GetCurrentURL( &szCurrentURL ); this calls GetActiveWindow which is extrememly inaccurate and unnneeded.
|
||
|
m_pOuter->m_pWebBrowserApp->GetLocationURL( &szCurrentURL );
|
||
|
pszJumpURL = szCurrentURL.psz;
|
||
|
if( !pszJumpURL || !*pszJumpURL )
|
||
|
return;
|
||
|
uiURLType = GetURLType( pszJumpURL ); // reset the type
|
||
|
}
|
||
|
|
||
|
CExCollection* pCollection = NULL;
|
||
|
CExTitle* pTitle = NULL;
|
||
|
BOOL bEnable = FALSE;
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
// check if this is a compiled file (one of ours) first
|
||
|
BOOL bCompiled = (uiURLType != HH_URL_UNKNOWN);
|
||
|
|
||
|
// is this a super automagic URL?
|
||
|
//
|
||
|
// if not a compiled name check if it is a super automagic URL
|
||
|
// that is it is of the form: mytitle.chm::/mytopic.htm
|
||
|
// if so, then prefix it with our moniker, and continue on
|
||
|
//
|
||
|
// Note, the automagic URL support below will take care
|
||
|
// of fully qualifying the path and retry the navigate
|
||
|
CHHWinType* phh = FindHHWindowIndex(m_pOuter);
|
||
|
|
||
|
if(phh)
|
||
|
phh->m_bCancel = TRUE;
|
||
|
|
||
|
char szURL[MAX_URL];
|
||
|
BOOL bWasPrefixLess = FALSE;
|
||
|
if( uiURLType == HH_URL_PREFIX_LESS ) {
|
||
|
bWasPrefixLess = TRUE;
|
||
|
strcpy( szURL, (g_bMsItsMonikerSupport ? txtMsItsMoniker : txtMkStore) );
|
||
|
strcat( szURL, pszJumpURL );
|
||
|
pszJumpURL = szURL;
|
||
|
uiURLType = HH_URL_UNQUALIFIED;
|
||
|
}
|
||
|
|
||
|
// The moniker gets first crack at finding the title and thus if the specified
|
||
|
// title is found in the current directory than the moniker will fully qualify
|
||
|
// the URL and we only find out about it here first (the finder is never called).
|
||
|
//
|
||
|
// Thus, given a qualified URL we still have to check if it is external and if
|
||
|
// so we need to call the same "init and re-navigate" as we do for the automagic
|
||
|
// form of an external title.
|
||
|
//
|
||
|
if( phh && (uiURLType == HH_URL_QUALIFIED) ) {
|
||
|
if( pCollection = GetCurrentCollection(NULL, pszJumpURL) ) {
|
||
|
hr = pCollection->URL2ExTitle( pszJumpURL, &pTitle );
|
||
|
if( !pTitle ) {
|
||
|
// we now know that we have an external URL
|
||
|
// so do our "init and re-navigate" thing
|
||
|
GetCompiledName( pszJumpURL, &PathName );
|
||
|
bInitNewTitle = TRUE;
|
||
|
bNewNavigate = TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// is this an automagic URL?
|
||
|
//
|
||
|
// if so, convert the URL to the fully qualified URL (if necessary) and then\
|
||
|
// re-navigate so that IE uses and knows about the the fully qualified URL
|
||
|
//
|
||
|
// we now have to support a new URL format for compiled files. The format is:
|
||
|
//
|
||
|
// mk:@MSITStore:mytitle.chm::/dir/mytopic.htm
|
||
|
//
|
||
|
// where "mk:@MSITStore:" can take any one of the many forms of our URL
|
||
|
// prefix and it may be optional. The "mytitle.chm" substring may or
|
||
|
// may not be a full pathname to the title. The remaining part is simply
|
||
|
// the pathname inside of the compiled title.
|
||
|
//
|
||
|
// When the URL is in this format, we need to change it to the fully
|
||
|
// qualified URL format which is:
|
||
|
//
|
||
|
// mk:@MSITStore:c:\titles\mytitle.chm::/dir/mytopic.htm
|
||
|
//
|
||
|
// where "mytitle.chm" is now changed to the full path name
|
||
|
// of the installed title "c:\titles\mytitle.chm".
|
||
|
//
|
||
|
char szJumpURL[MAX_URL];
|
||
|
if( phh && (uiURLType == HH_URL_UNQUALIFIED) ) {
|
||
|
if( pCollection = GetCurrentCollection(NULL, pszJumpURL) ) {
|
||
|
hr = pCollection->URL2ExTitle( pszJumpURL, &pTitle );
|
||
|
|
||
|
// If there is no title associated with this URL in the
|
||
|
// collection and this URL was previously a prefix-less
|
||
|
// URL then this means we probably have an external
|
||
|
// title reference and thus we need to resend the new
|
||
|
// unqualified URL through again and have it eventually
|
||
|
// call the finder where it will try to locate the file
|
||
|
// and jump to the topic.
|
||
|
//
|
||
|
// Note, since such a jump eventually is resolved via the finder
|
||
|
// this means that IE will not know about the fully qualified
|
||
|
// path and thus the usual secondary window jump problems
|
||
|
// and and the like will surface if the user navigates via this
|
||
|
// new topic.
|
||
|
//
|
||
|
// To solve the problem we should port over the same code found
|
||
|
// in the finder that handles the external URL condition and simply
|
||
|
// do in here inline and repost this newly qualified URL instead.
|
||
|
//
|
||
|
|
||
|
if( pTitle )
|
||
|
pTitle->ConvertURL( pszJumpURL, szJumpURL );
|
||
|
|
||
|
// IE3 appears to automatically translate %20 into a space.
|
||
|
// Thus, in order to determine if the URL has changed or not
|
||
|
// we are going to have to put both URLs into a canonical form
|
||
|
// and do the string compare.
|
||
|
//
|
||
|
// Note, technically szJumpURL is already in canonical form
|
||
|
// since ConvertURL does this for us but it is better to be safe
|
||
|
// and convert it again. Yes, I am being paranoid but this code
|
||
|
// make me so!
|
||
|
//
|
||
|
CStr TestURL1;
|
||
|
CStr TestURL2;
|
||
|
if( pTitle ) {
|
||
|
ConvertSpacesToEscapes( szJumpURL, &TestURL1 );
|
||
|
ConvertSpacesToEscapes( pszJumpURL, &TestURL2 );
|
||
|
}
|
||
|
|
||
|
if( !pTitle || StrCmpIA( TestURL1.psz, TestURL2.psz ) != 0 ) {
|
||
|
if( pTitle ) {
|
||
|
pszJumpURL = szJumpURL;
|
||
|
}
|
||
|
else {
|
||
|
// we need to add this new title to the list
|
||
|
GetCompiledName( pszJumpURL, &PathName );
|
||
|
|
||
|
// check if it is in the same dir as the master
|
||
|
char szPathName[_MAX_PATH];
|
||
|
char szFileName[_MAX_FNAME]; // add back the extension to this post-SplitPath
|
||
|
char szExtension[_MAX_EXT];
|
||
|
SplitPath((LPSTR)PathName.psz, NULL, NULL, szFileName, szExtension);
|
||
|
strcat( szFileName, szExtension );
|
||
|
char szMasterPath[_MAX_PATH];
|
||
|
char szMasterDrive[_MAX_DRIVE];
|
||
|
SplitPath((LPSTR)pCollection->m_csFile, szMasterDrive, szMasterPath, NULL, NULL);
|
||
|
strcpy( szPathName, szMasterDrive );
|
||
|
CatPath( szPathName, szMasterPath );
|
||
|
CatPath( szPathName, szFileName );
|
||
|
if( (GetFileAttributes(szPathName) != HFILE_ERROR) ) {
|
||
|
PathName = szPathName;
|
||
|
}
|
||
|
else { // try the dreaded ::FindThisFile
|
||
|
if( !::FindThisFile( NULL, szFileName, &PathName, FALSE ) ) {
|
||
|
*pfCancel = TRUE;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
bInitNewTitle = TRUE;
|
||
|
}
|
||
|
bNewNavigate = TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// do we need to init this as a new title?
|
||
|
if( bInitNewTitle ) {
|
||
|
lParam = (LPARAM) (PSTR) LocalAlloc( LMEM_FIXED, strlen(PathName.psz)+1 );
|
||
|
strcpy( (PSTR) lParam, PathName.psz );
|
||
|
}
|
||
|
|
||
|
// do we need to re-navigate to a new URL?
|
||
|
if( bNewNavigate ) {
|
||
|
#if 1
|
||
|
wParam = (WPARAM) (PSTR) LocalAlloc( LMEM_FIXED, strlen(pszJumpURL)+1 );
|
||
|
strcpy( (PSTR) wParam, pszJumpURL );
|
||
|
PostMessage( phh->GetHwnd(), WMP_JUMP_TO_URL, wParam, lParam );
|
||
|
#else
|
||
|
phh->m_pCIExpContainer->m_pWebBrowserApp->Navigate( pszJumpURL, NULL, NULL, NULL, NULL );
|
||
|
#endif
|
||
|
|
||
|
*pfCancel = TRUE;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// get a pointer to the title
|
||
|
if( bCompiled ) {
|
||
|
pCollection = GetCurrentCollection(NULL, pszJumpURL);
|
||
|
if( pCollection ) {
|
||
|
if( !pTitle )
|
||
|
hr = pCollection->URL2ExTitle( pszJumpURL, &pTitle );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Removable media support.
|
||
|
//
|
||
|
// if this is a topic in a chm file then ensure the storage is available
|
||
|
// make sure it is one of our files and not a random URL
|
||
|
//
|
||
|
// Note, this must be one of the first things we do since the URL can change
|
||
|
// if the user changes the title location
|
||
|
//
|
||
|
// Note, we cannot fully move this code into HHFinder since HHFinder has
|
||
|
// no ability to cancel the jump if the user dismisses the swap dialog. All
|
||
|
// we can do is duplicate the code in HHFinder as a fallback for such cases
|
||
|
// as the user pressing Refresh (which does not call BeforeNavigate)!
|
||
|
//
|
||
|
// Now that we have to support automagic URLs inline we are going to have
|
||
|
// to detect if the pathname changed between CD swapping. If so, then we
|
||
|
// are going to have to reissue the jump so that IE gets/knows about the fully
|
||
|
// qualified URL.
|
||
|
//
|
||
|
// Note, this only works for .col collections so skip the check for single title
|
||
|
// and merge sets
|
||
|
//
|
||
|
char szJumpURL2[MAX_URL];
|
||
|
if( bCompiled && phh && pCollection && !(pCollection->IsSingleTitle()) ) {
|
||
|
if( !pTitle )
|
||
|
hr = pCollection->URL2ExTitle( pszJumpURL, &pTitle );
|
||
|
if( FAILED(hr = EnsureStorageAvailability( pTitle )) ) {
|
||
|
if( hr == HHRMS_E_SKIP_ALWAYS )
|
||
|
MsgBox(IDS_TOPIC_UNAVAILABLE);
|
||
|
if( hr != E_FAIL )
|
||
|
*pfCancel = TRUE;
|
||
|
phh->m_fHighlight = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
else {
|
||
|
if( hr == HHRMS_S_LOCATION_UPDATE ) {
|
||
|
// fetch the new URL and try again
|
||
|
pTitle->ConvertURL( pszJumpURL, szJumpURL2 );
|
||
|
pszJumpURL = szJumpURL2;
|
||
|
*pfCancel = TRUE;
|
||
|
|
||
|
#if 1
|
||
|
PSTR psz = (PSTR) LocalAlloc( LMEM_FIXED, strlen(pszJumpURL)+1 );
|
||
|
strcpy( psz, pszJumpURL );
|
||
|
PostMessage( phh->GetHwnd(), WMP_JUMP_TO_URL, (WPARAM) psz, 0 );
|
||
|
#else
|
||
|
phh->m_pCIExpContainer->m_pWebBrowserApp->Navigate( pszJumpURL, NULL, NULL, NULL, NULL );
|
||
|
#endif
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if this is not a jump then bail out
|
||
|
if( !bJump )
|
||
|
return;
|
||
|
|
||
|
// make sure the chm/chi pairs match
|
||
|
//
|
||
|
if( bCompiled && pTitle ) {
|
||
|
if( !pTitle->EnsureChmChiMatch() ) {
|
||
|
*pfCancel = TRUE;
|
||
|
phh->m_fHighlight = FALSE;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// This bit of code tells the collection where we think we are in the TOC. This is used for next and prev in the
|
||
|
// TOC as well as any direct jump from the TOC. We can use this data (topic number and toc location information)
|
||
|
// and compare it aginst the the information we get directly from the TOC to try and determine if we are navigating
|
||
|
// to a topic that is referenced in multiple locations in the TOC. This make sync work much more reliably. As a
|
||
|
// side affect, this code will also end up making autosync a little faster as well for binary TOC. Note also it
|
||
|
// relies upon some setup work done in the removable media support code above. <mc>
|
||
|
//
|
||
|
// Update TOC "slot" and topic information here since we have decided to allow the navigation to proceed.
|
||
|
//
|
||
|
if ( phh && pCollection && pCollection->IsBinaryTOC(phh->pszToc) )
|
||
|
{
|
||
|
if ( SUCCEEDED(pCollection->URL2ExTitle( pszJumpURL, &pTitle )) || (pTitle = pCollection->GetCurSyncExTitle()) )
|
||
|
{
|
||
|
DWORD dwSlot, dwTN;
|
||
|
if (! SUCCEEDED(pTitle->GetUrlTocSlot(pszJumpURL, &dwSlot, &dwTN)) )
|
||
|
{
|
||
|
dwSlot = 0;
|
||
|
dwTN = 0;
|
||
|
}
|
||
|
pCollection->UpdateTopicSlot(dwSlot, dwTN, pTitle);
|
||
|
if ( dwSlot )
|
||
|
bEnable = TRUE;
|
||
|
}
|
||
|
}
|
||
|
if ( phh && IsValidWindow(phh->hwndToolBar) && (phh->fsToolBarFlags & HHWIN_BUTTON_SYNC) )
|
||
|
{
|
||
|
if (pCollection && (! pCollection->IsBinaryTOC(phh->pszToc)) )
|
||
|
bEnable = TRUE; // Always enable sync or "locate" button for sitemap.
|
||
|
SendMessage(phh->hwndToolBar, TB_ENABLEBUTTON, IDTB_SYNC, bEnable);
|
||
|
HMENU hMenu = NULL;
|
||
|
if ( phh->hwndHelp )
|
||
|
hMenu = GetMenu(phh->hwndHelp);
|
||
|
if ( hMenu )
|
||
|
EnableMenuItem(hMenu, HHM_SYNC, (MF_BYCOMMAND | (bEnable?MF_ENABLED:MF_GRAYED)));
|
||
|
}
|
||
|
if(!*pfCancel)
|
||
|
phh->m_bCancel = FALSE;
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void CAutomateContent::OnNavigateComplete(LPCTSTR pszURL)
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
char sz[MAX_URL];
|
||
|
wsprintf(sz, "OnNavigateComplete Event Called: %s", pszURL);
|
||
|
DBWIN(sz);
|
||
|
#endif
|
||
|
|
||
|
// if (m_pPrintHook != NULL)
|
||
|
// m_pPrintHook->OnNavigateComplete();
|
||
|
|
||
|
CHHWinType* phh = FindHHWindowIndex(m_pOuter);
|
||
|
if (phh)
|
||
|
phh->OnNavigateComplete(pszURL);
|
||
|
|
||
|
if ( g_fIE3 )
|
||
|
OnDocumentComplete();
|
||
|
}
|
||
|
|
||
|
void CAutomateContent::OnDocumentComplete()
|
||
|
{
|
||
|
CHHWinType* phh = FindHHWindowIndex(m_pOuter);
|
||
|
CToc* ptoc = NULL;
|
||
|
|
||
|
// Bug 4710. This bit of code allows us to get focus right when we come need to init the focus to
|
||
|
// our ie host.
|
||
|
//
|
||
|
if ( m_bFirstTime )
|
||
|
{
|
||
|
m_bFirstTime = FALSE;
|
||
|
if ( (phh->fNotExpanded == TRUE) && phh->m_pCIExpContainer )
|
||
|
phh->m_pCIExpContainer->SetFocus(TRUE);
|
||
|
}
|
||
|
|
||
|
// Get a pointer to the toc if it exists.
|
||
|
if (phh && phh->m_aNavPane[HH_TAB_CONTENTS])
|
||
|
ptoc = reinterpret_cast<CToc*>(phh->m_aNavPane[HH_TAB_CONTENTS]) ; // HACKHACK: Should use dynamic cast, but no RTTI.
|
||
|
//
|
||
|
// Do autosync if necessary.
|
||
|
//
|
||
|
// <mc>
|
||
|
// I've moved the autosync and UI update code from DownloadComplete() because we ALWAYS get this call. We do
|
||
|
// not get DownloadComplete() calls when we navigate from one anchor point to another within the same .HTM file.
|
||
|
// 12-15-97
|
||
|
// </mc>
|
||
|
//
|
||
|
if (phh && phh->IsProperty(HHWIN_PROP_AUTO_SYNC) && ptoc)
|
||
|
{
|
||
|
CStr cszUrl;
|
||
|
phh->m_pCIExpContainer->m_pWebBrowserApp->GetLocationURL(&cszUrl);
|
||
|
if (cszUrl.IsNonEmpty())
|
||
|
{
|
||
|
ptoc->Synchronize(cszUrl.psz);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( phh )
|
||
|
phh->UpdateCmdUI();
|
||
|
|
||
|
// highlight search terms
|
||
|
//
|
||
|
|
||
|
if(phh && phh->m_fHighlight && !phh->m_bCancel)
|
||
|
{
|
||
|
phh->m_fHighlight = FALSE;
|
||
|
LPDISPATCH lpDispatch = m_pOuter->m_pWebBrowserApp->GetDocument();
|
||
|
if(lpDispatch)
|
||
|
{
|
||
|
HWND hWnd = GetFocus();
|
||
|
// UI active shdocvw to work around Trident bug
|
||
|
//
|
||
|
if (! phh->m_pCIExpContainer->m_pInPlaceActive )
|
||
|
phh->m_pCIExpContainer->m_pOleObject->DoVerb(OLEIVERB_UIACTIVATE, NULL, phh->m_pCIExpContainer->m_pIOleClientSite, -1,phh->m_pCIExpContainer->m_hWnd, NULL);
|
||
|
|
||
|
// Highlight the document
|
||
|
//
|
||
|
phh->m_phmData->m_pTitleCollection->m_pSearchHighlight->HighlightDocument(lpDispatch);
|
||
|
lpDispatch->Release();
|
||
|
|
||
|
// deactivate shdocvw UI after highlighting
|
||
|
//
|
||
|
phh->m_pCIExpContainer->UIDeactivateIE();
|
||
|
SetFocus(hWnd);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// set focus back to previous control after navigate
|
||
|
if (phh && phh->m_hwndControl)
|
||
|
{
|
||
|
SetFocus(phh->m_hwndControl);
|
||
|
phh->m_hwndControl = NULL;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void CAutomateContent::OnTitleChange(LPCTSTR pszTitle)
|
||
|
{
|
||
|
DBWIN("OnTitleChange Event Called.");
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
CHHWinType* phh = FindHHWindowIndex(m_pOuter);
|
||
|
if (phh) {
|
||
|
CStr cszUrl;
|
||
|
phh->m_pCIExpContainer->m_pWebBrowserApp->GetLocationURL(&cszUrl);
|
||
|
if (cszUrl.IsNonEmpty() && strcmp(cszUrl, pszTitle) != 0)
|
||
|
phh->AddToHistory(pszTitle, cszUrl);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
CHHWinType* FindHHWindowIndex(CContainer* m_pOuter)
|
||
|
{
|
||
|
static iLastWindow = 0;
|
||
|
if (pahwnd[iLastWindow] && (pahwnd[iLastWindow]->m_pCIExpContainer == m_pOuter))
|
||
|
return pahwnd[iLastWindow];
|
||
|
|
||
|
for (iLastWindow = 0; iLastWindow < g_cWindowSlots; iLastWindow++) {
|
||
|
if (pahwnd[iLastWindow] && pahwnd[iLastWindow]->m_pCIExpContainer == m_pOuter)
|
||
|
return pahwnd[iLastWindow];
|
||
|
}
|
||
|
iLastWindow = 0;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
#if 0
|
||
|
void CAutomateContent::OnProgressChange(long Progress, long ProgressMax)
|
||
|
{
|
||
|
DBWIN("OnProgressChange Event Called.");
|
||
|
|
||
|
if (Progress < 0)
|
||
|
{
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
void CAutomateContent::OnPropertyChange(LPCTSTR pszProperty)
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
char sz[256];
|
||
|
wsprintf(sz, "OnPropertyChange Event Called: %s", pszProperty);
|
||
|
DBWIN(sz);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void CAutomateContent::OnQuit(BOOL* pfCancel)
|
||
|
{
|
||
|
DBWIN("OnQuit Event Called.");
|
||
|
}
|
||
|
|
||
|
void CAutomateContent::OnStatusTextChange(LPCTSTR pszText)
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
char sz[256];
|
||
|
wsprintf(sz, "OnStatusTextChange Event Called: %s", pszText);
|
||
|
DBWIN(sz);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void CAutomateContent::OnWindowActivated()
|
||
|
{
|
||
|
DBWIN("OnWindowActivated Event Called.");
|
||
|
}
|