windows-nt/Source/XPSP1/NT/shell/shdocvw/iedde.cpp
2020-09-26 16:20:57 +08:00

2841 lines
75 KiB
C++

/* Copyright 1996 Microsoft */
#include "priv.h"
#ifdef DEBUG
#define ENTERPROC EnterProc
#define EXITPROC ExitProc
void EnterProc(DWORD dwTraceLevel, LPTSTR szFmt, ...);
void ExitProc(DWORD dwTraceLevel, LPTSTR szFmt, ...);
extern DWORD g_dwIEDDETrace;
#else
#pragma warning(disable:4002)
#ifndef UNIX
#ifndef CCOVER
#define ENTERPROC()
#define EXITPROC()
#else //CCOVER
// these are needed because of a bug in cl.exe which causes
// compilation problems with #pragma when a program is preprocessed
// and compiled separately
#define ENTERPROC 1 ? (void) 0 : (void)
#define EXITPROC 1 ? (void) 0 : (void)
#endif // CCOVER
#else
#define ENTERPROC EnterProc
#define EXITPROC ExitProc
inline void EnterProc(DWORD dwTraceLevel, LPTSTR szFmt, ...){}
inline void ExitProc(DWORD dwTraceLevel, LPTSTR szFmt, ...){}
#endif
#endif
//
// Forward reference.
//
class CIEDDEThread;
//
// Stored in _hdsaWinitem
//
typedef struct _tagWinItem
{
DWORD dwWindowID; // Synthetic window ID exposed in IEDDE interfaces
HWND hwnd; // Actual hwnd of browser window
DWORD dwThreadID; // ThreadID for this browser window
CIEDDEThread *pidt; // Thread specific data and methods
} WINITEM;
//
// Stored in _hdsaProtocolHandler
//
typedef struct _tagProtocolReg
{
LPTSTR pszProtocol;
LPTSTR pszServer;
} PROTOCOLREG;
#define TEN_SECONDS (10 * 1000)
#define DXA_GROWTH_AMOUNT (10)
#ifndef UNIX
#define IEXPLORE_STR "IEXPLORE"
#else
#define IEXPLORE_STR "iexplorer"
#endif
static const TCHAR c_szIExplore[] = TEXT(IEXPLORE_STR);
static const TCHAR c_szReturn[] = TEXT("Return");
static const TCHAR c_szWWWOpenURL[] = TEXT("WWW_OpenURL");
static const TCHAR c_szWWWUrlEcho[] = TEXT("WWW_URLEcho");
typedef struct _tagDDETHREADINFO
{
DWORD dwDDEInst;
HSZ hszService;
HSZ hszReturn;
HDDEDATA hddNameService;
} DDETHREADINFO;
class CIEDDEThread {
public:
CIEDDEThread() { };
~CIEDDEThread() { };
void GetDdeThreadInfo(DDETHREADINFO *pdti) { *pdti = _dti; }
void SetDdeThreadInfo(DDETHREADINFO *pdti) { _dti = *pdti; }
HDDEDATA OnRequestPoke(HSZ hszTopic, HSZ hszParams);
HDDEDATA OnExecute(HSZ hszTopic, HDDEDATA hddParams);
HDDEDATA CallTopic(DWORD dwType, LPCTSTR pszTopic, LPTSTR pszParams);
protected:
DDETHREADINFO _dti;
HDDEDATA DoNavigate(LPTSTR pszLocation, HWND hwnd, BOOL bLaunchNewWindow);
BOOL MakeQuotedString(LPCTSTR pszInput, LPTSTR pszOutput, int cchOutput);
HDDEDATA CreateReturnObject(LPVOID p, DWORD cb);
HDDEDATA CreateReturnStringObject(LPTSTR pszReturnString, DWORD cch);
BOOL ParseString(LPTSTR *ppsz, LPTSTR *ppszString);
BOOL ParseQString(LPTSTR *ppsz, LPTSTR *ppszString);
BOOL ParseNumber(LPTSTR *ppsz, DWORD *pdw);
BOOL ParseWinitem(LPTSTR *ppsz, WINITEM *pwi);
HDDEDATA WWW_GetWindowInfo(LPTSTR pszParams);
HDDEDATA WWW_OpenURL(LPTSTR pszParams);
HDDEDATA WWW_OpenURLNewWindow(LPTSTR pszParams);
HDDEDATA WWW_ShowFile(LPTSTR pszParams);
HDDEDATA WWW_Activate(LPTSTR pszParams);
HDDEDATA WWW_Exit(LPTSTR pszParams);
HDDEDATA WWW_RegisterURLEcho(LPTSTR pszParams);
HDDEDATA WWW_UnregisterURLEcho(LPTSTR pszParams);
HDDEDATA WWW_RegisterProtocol(LPTSTR pszParams);
HDDEDATA WWW_UnregisterProtocol(LPTSTR pszParams);
HDDEDATA WWW_ListWindows(LPTSTR pszParams);
};
class CIEDDE {
public:
CIEDDE() { };
~CIEDDE() { };
BOOL IsAutomationReady(void) { return _fAutomationReady; }
BOOL GetWinitemFromWindowID(DWORD dwWindowID, WINITEM *pwi);
BOOL GetWinitemFromHwnd(HWND hwnd, WINITEM *pwi);
BOOL AddUrlEcho(LPCTSTR pszUrlEcho);
BOOL RemoveUrlEcho(LPCTSTR pszUrlEcho);
BOOL AddProtocolHandler(LPCTSTR pszServer, LPCTSTR pszProtocol);
BOOL RemoveProtocolHandler(LPCTSTR pszServer, LPCTSTR pszProtocol);
HDSA GetHdsaWinitem(void) { return _hdsaWinitem; }
static HDDEDATA DdeCallback(UINT dwType, UINT dwFmt, HCONV hconv, HSZ hsz1, HSZ hsz2, HDDEDATA hdd, DWORD dwData1, DWORD dwData2);
void EnterCrit(void) { ASSERT(_fCSInitialized); EnterCriticalSection(&_csIEDDE); }
void LeaveCrit(void) { ASSERT(_fCSInitialized); LeaveCriticalSection(&_csIEDDE); }
void SetDelayedExecute(LPCTSTR pszTopic, LPCTSTR pszParams);
void RunDelayedExecute();
protected:
BOOL _fAutomationReady;
HDSA _hdsaWinitem;
HDSA _hdsaProtocolHandler;
HDPA _hdpaUrlEcho;
BOOL _fCSInitialized;
CRITICAL_SECTION _csIEDDE;
DWORD _dwThreadID;
LPTSTR _pszTopic;
LPTSTR _pszParams;
HDDEDATA _SendDDEMessageHsz(DWORD dwDDEInst, HSZ hszApp, HSZ hszTopic, HSZ hszMessage, UINT wType);
HDDEDATA _SendDDEMessageSz(DWORD dwDDEInst, LPCTSTR pszApp, LPCTSTR pszTopic, LPCTSTR pszMessage, UINT wType);
static int _DestroyProtocol(LPVOID p1, LPVOID p2);
static int _DestroyUrlEcho(LPVOID p1, LPVOID p2);
static int _DestroyWinitem(LPVOID p1, LPVOID p2);
BOOL _GetWinitemFromThread(DWORD dwThreadID, WINITEM *pwi);
BOOL _GetDtiFromThread(DWORD dwThreadID, DDETHREADINFO *pdti);
BOOL _CreateDdeThreadInfo(DDETHREADINFO *pdti);
void _DestroyDdeThreadInfo(DDETHREADINFO *pdti);
BOOL _AddWinitem(WINITEM *pwi);
BOOL _UpdateWinitem(WINITEM *pwi);
BOOL _DeleteWinitemByHwnd(HWND hwnd, WINITEM *pwi);
BOOL _Initialize(void);
void _Uninitialize(void);
void _AutomationStarted(void);
HRESULT _BeforeNavigate(LPCTSTR pszURL, BOOL *pfProcessed);
HRESULT _AfterNavigate(LPCTSTR pszURL, HWND hwnd);
BOOL _NewWindow(HWND hwnd);
BOOL _WindowDestroyed(HWND hwnd);
friend BOOL IEDDE_Initialize(void);
friend void IEDDE_Uninitialize(void);
friend void IEDDE_AutomationStarted(void);
friend HRESULT IEDDE_BeforeNavigate(LPCWSTR pwszURL, BOOL *pfProcessed);
friend HRESULT IEDDE_AfterNavigate(LPCWSTR pwszURL, HWND hwnd);
friend BOOL IEDDE_NewWindow(HWND hwnd);
friend BOOL IEDDE_WindowDestroyed(HWND hwnd);
};
CIEDDE *g_pIEDDE = NULL;
#define ENTER_IEDDE_CRIT g_pIEDDE->EnterCrit()
#define LEAVE_IEDDE_CRIT g_pIEDDE->LeaveCrit()
//
// There is one CIEDDEThread object per browser window.
// Its private data consists of DDE handles, which are
// necessarily valid only in the thread that created them.
//
// Its methods consist of three broad categories:
// the parser
// the dispatcher
// one handler for each DDE topic
//
//
// CreateReturnObject - creates a dde data item.
//
#define CREATE_HDD(x) CreateReturnObject(&x, SIZEOF(x))
HDDEDATA CIEDDEThread::CreateReturnObject(LPVOID p, DWORD cb)
{
HDDEDATA hddRet;
ENTERPROC(2, TEXT("CreateReturnObject(p=%08X,cb=%d)"), p, cb);
hddRet = DdeCreateDataHandle(_dti.dwDDEInst, (BYTE *)p, cb, 0, _dti.hszReturn, CF_TEXT, 0);
if (hddRet == 0)
{
TraceMsg(TF_WARNING, "IEDDE: Could not create return object");
}
EXITPROC(2, TEXT("CreateReturnObject=%08X"), hddRet);
return hddRet;
}
HDDEDATA CIEDDEThread::CreateReturnStringObject(LPTSTR pszReturnString, DWORD cch)
{
HDDEDATA hddRet = 0;
ENTERPROC(2, TEXT("CreateReturnStringObject(p=%s,cb=%d)"), pszReturnString, cch);
//
// REVIEW I thought specifying CF_UNICODETEXT should have worked, but...
// it didn't, so always return ANSI string as out string params
// - julianj
//
LPSTR pszAnsiBuf = (LPSTR)LocalAlloc(LPTR, cch+1);
if (pszAnsiBuf)
{
SHUnicodeToAnsi(pszReturnString, pszAnsiBuf, cch+1);
hddRet = DdeCreateDataHandle(_dti.dwDDEInst, (BYTE *)pszAnsiBuf, (cch+1), 0, _dti.hszReturn, CF_TEXT, 0);
LocalFree(pszAnsiBuf);
pszAnsiBuf = NULL;
}
if (hddRet == 0)
{
TraceMsg(TF_WARNING, "IEDDE: Could not create return object");
}
EXITPROC(2, TEXT("CreateReturnObject=%08X"), hddRet);
return hddRet;
}
//
// OnRequestPoke - handle XTYP_REQUEST and XTYP_POKE
//
HDDEDATA CIEDDEThread::OnRequestPoke(HSZ hszTopic, HSZ hszParams)
{
HDDEDATA hddRet = 0;
ENTERPROC(2, TEXT("OnRequestPoke(hszTopic=%08X,hszParams=%08X)"), hszTopic, hszParams);
TCHAR szTopic[100];
TCHAR szParams[1000];
if (DdeQueryString(_dti.dwDDEInst, hszTopic, szTopic, ARRAYSIZE(szTopic), CP_WINNEUTRAL) != 0)
{
if (DdeQueryString(_dti.dwDDEInst, hszParams, szParams, ARRAYSIZE(szParams), CP_WINNEUTRAL))
{
hddRet = CallTopic(XTYP_REQUEST, szTopic, szParams);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: OnRequestPoke could not query the parameters");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: OnRequestPoke could not query the topic");
}
EXITPROC(2, TEXT("OnRequestPoke=%08X"), hddRet);
return hddRet;
}
//
// OnExecute - handle XTYP_EXECUTE
//
HDDEDATA CIEDDEThread::OnExecute(HSZ hszTopic, HDDEDATA hddParams)
{
HDDEDATA hddRet = 0;
ENTERPROC(2, TEXT("OnExecute(hszTopic=%08X,hddParams=%08X)"), hszTopic, hddParams);
TCHAR szTopic[100];
if (DdeQueryString(_dti.dwDDEInst, hszTopic, szTopic, ARRAYSIZE(szTopic), CP_WINNEUTRAL) != 0)
{
//
// Why "cbParams + 3"?
// UNICODE - if we cut the last unicode character in half, we need
// one 0 to finish the character, and two more 0 for the
// terminating NULL
// ANSI - if we cut the last DBCS character in half, we need one 0
// to finish the character, and one 0 for the terminating NULL
//
//
DWORD cbParams = DdeGetData(hddParams, NULL, 0, 0) + 3;
LPTSTR pszParams = (LPTSTR) LocalAlloc(LPTR, cbParams);
if(pszParams)
{
DdeGetData(hddParams, (BYTE *)pszParams, cbParams, 0);
//
// DdeGetData can't be wrapped in shlwapi since it can return non
// string data. Here we only expect strings so the result can be
// safely converted.
//
if (g_fRunningOnNT)
{
hddRet = CallTopic(XTYP_EXECUTE, szTopic, pszParams);
}
else
{
WCHAR szParams[MAX_URL_STRING];
SHAnsiToUnicode((LPCSTR)pszParams, szParams, ARRAYSIZE(szParams));
hddRet = CallTopic(XTYP_EXECUTE, szTopic, szParams);
}
LocalFree(pszParams);
pszParams = NULL;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: OnExecute could not query the topic");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: OnExecute could not query the topic");
}
EXITPROC(2, TEXT("OnExecute=%08X"), hddRet);
return hddRet;
}
//
// CallTopic - Looks up the command in the DDETOPICHANDLER table and calls the
// corresponding function.
//
HDDEDATA CIEDDEThread::CallTopic(DWORD dwType, LPCTSTR pszTopic, LPTSTR pszParams)
{
HDDEDATA hddRet = DDE_FNOTPROCESSED;
ENTERPROC(2, TEXT("CallTopic(wType=%d,pszTopic=>%s<,pszParams=>%s<)"), dwType, pszTopic, pszParams);
#define DISPATCH_BEGIN
#define DISPATCH(topic) \
if (StrCmpI(TEXT("WWW_") TEXT(#topic), pszTopic) == 0) \
{ \
if (fCanRun) \
{ \
hddRet = WWW_ ## topic(pszParams); \
} \
else \
{ \
fAbortedRun = TRUE; \
} \
} \
else
#define DISPATCH_END { TraceMsg(TF_WARNING, "IEDDE: CallTopic given unknown topic"); }
BOOL fAbortedRun = FALSE;
BOOL fCanRun = ((dwType != XTYP_EXECUTE) || g_pIEDDE->IsAutomationReady());
DISPATCH_BEGIN
DISPATCH(GetWindowInfo)
DISPATCH(OpenURL)
DISPATCH(ShowFile)
DISPATCH(Activate)
DISPATCH(Exit)
DISPATCH(RegisterURLEcho)
DISPATCH(UnregisterURLEcho)
DISPATCH(RegisterProtocol)
DISPATCH(UnregisterProtocol)
DISPATCH(ListWindows)
DISPATCH(OpenURLNewWindow)
DISPATCH_END
if (fAbortedRun)
{
if (dwType == XTYP_EXECUTE)
{
g_pIEDDE->SetDelayedExecute(pszTopic, pszParams);
}
hddRet = (HDDEDATA)DDE_FACK;
TraceMsg(TF_WARNING, "IEDDE: CallTopic received XTYP_EXECUTE before Automation was ready - not processing");
}
EXITPROC(2, TEXT("CallTopic=%08X"), hddRet);
return hddRet;
}
//
// ParseString - parse one string
//
BOOL CIEDDEThread::ParseString(LPTSTR *ppsz, LPTSTR *ppszString)
{
BOOL fRet = FALSE;
ENTERPROC(3, TEXT("ParseString(ppsz=%08X,ppszString=%08X)"), ppsz, ppszString);
LPTSTR pchCurrent, pchNext;
BOOL fInQuote = FALSE;
pchCurrent = pchNext = *ppsz;
while (*pchNext)
{
switch (*pchNext)
{
case TEXT(' '):
case TEXT('\t'):
if (fInQuote)
{
//
// Skip over whitespace when not inside quotes.
//
*pchCurrent++ = *pchNext;
}
pchNext++;
break;
case TEXT('"'):
//
// Always copy quote marks.
//
fInQuote = !fInQuote;
*pchCurrent++ = *pchNext++;
break;
case TEXT(','):
if (!fInQuote)
{
goto done_parsing;
}
*pchCurrent++ = *pchNext++;
break;
case TEXT('\\'):
if (fInQuote &&
(*(pchNext+1) == TEXT('"')))
{
//
// When in quotes, a \" becomes a ".
//
pchNext++;
}
*pchCurrent++ = *pchNext++;
break;
default:
*pchCurrent++ = *pchNext++;
break;
}
}
done_parsing:
//
// Advance past the comma separator.
//
if (*pchNext == TEXT(','))
{
pchNext++;
}
//
// NULL terminate the return string.
//
*pchCurrent = TEXT('\0');
//
// Set the return values.
//
*ppszString = *ppsz;
*ppsz = pchNext;
fRet = TRUE;
EXITPROC(3, TEXT("ParseString=%d"), fRet);
return fRet;
}
//
// ParseQString - parse one quoted string
//
BOOL CIEDDEThread::ParseQString(LPTSTR *ppsz, LPTSTR *ppszString)
{
BOOL fRet = FALSE;
ENTERPROC(3, TEXT("ParseQString(ppsz=%08X,ppszString=%08X)"), ppsz, ppszString);
if (ParseString(ppsz, ppszString))
{
LPTSTR pszString = *ppszString;
int cch = lstrlen(pszString);
//
// Strip off optional outer quotes.
//
if ((cch >= 2) &&
(pszString[0] == TEXT('"')) &&
(pszString[cch-1] == TEXT('"')))
{
pszString[0] = pszString[cch-1] = TEXT('\0');
*ppszString = pszString + 1;
}
fRet = TRUE;
}
EXITPROC(3, TEXT("ParseQString=%d"), fRet);
return fRet;
}
//
// ParseNumber - parse one numeric value
//
BOOL CIEDDEThread::ParseNumber(LPTSTR *ppsz, DWORD *pdw)
{
BOOL fRet = FALSE;
LPTSTR pszNumber;
ENTERPROC(3, TEXT("GetNumber(ppsz=%08X,pdw=%08X)"), ppsz, pdw);
if (ParseString(ppsz, &pszNumber) && pszNumber[0])
{
StrToIntEx(pszNumber, STIF_SUPPORT_HEX, (int *)pdw);
fRet = TRUE;
}
EXITPROC(3, TEXT("GetNumber=%d"), fRet);
return fRet;
}
//
// ParseWinitem - parse one window ID, and return the winitem
//
BOOL CIEDDEThread::ParseWinitem(LPTSTR *ppsz, WINITEM *pwi)
{
BOOL fRet = FALSE;
DWORD dwWindowID;
ENTERPROC(3, TEXT("ParseWinitem(ppsz=%08X,pwi=%08X)"), ppsz, pwi);
if (ParseNumber(ppsz, &dwWindowID))
{
switch (dwWindowID)
{
case 0:
case -1:
ZeroMemory(pwi, SIZEOF(*pwi));
pwi->dwWindowID = dwWindowID;
pwi->hwnd = (HWND)LongToHandle(dwWindowID);
fRet = TRUE;
break;
default:
fRet = g_pIEDDE->GetWinitemFromWindowID(dwWindowID, pwi);
break;
}
}
EXITPROC(3, TEXT("ParseWinitem=%d"), fRet);
return fRet;
}
//
// WWW_GetWindowInfo - get information about a browser window
//
// Parameters:
// dwWindowID - Window ID to examine (-1 = last active window)
//
// Returns:
// qcsURL,qcsTitle
//
HDDEDATA CIEDDEThread::WWW_GetWindowInfo(LPTSTR pszParams)
{
HDDEDATA hddRet = 0;
WINITEM wi;
ENTERPROC(1, TEXT("WWW_GetWindowInfo(pszParams=>%s<)"), pszParams);
if (ParseWinitem(&pszParams, &wi) &&
(wi.hwnd != 0))
{
BSTR bstrURL;
if (SUCCEEDED(CDDEAuto_get_LocationURL(&bstrURL, wi.hwnd)) && (bstrURL != (BSTR)-1))
{
BSTR bstrTitle;
if (SUCCEEDED(CDDEAuto_get_LocationTitle(&bstrTitle, wi.hwnd)) && (bstrTitle != (BSTR)-1))
{
LPTSTR pszURL, pszTitle;
pszURL = bstrURL;
pszTitle = bstrTitle;
if (pszURL && pszTitle)
{
TCHAR szURLQ[MAX_URL_STRING];
TCHAR szTitleQ[MAX_URL_STRING];
if (MakeQuotedString(pszURL, szURLQ, ARRAYSIZE(szURLQ)) &&
MakeQuotedString(pszTitle, szTitleQ, ARRAYSIZE(szTitleQ)))
{
DWORD cchBuffer = lstrlen(szURLQ) + 1 + lstrlen(szTitleQ) + 1;
LPTSTR pszBuffer = (LPTSTR)LocalAlloc(LPTR, cchBuffer * SIZEOF(TCHAR));
if (pszBuffer)
{
wnsprintf(pszBuffer, cchBuffer, TEXT("%s,%s"), szURLQ, szTitleQ);
hddRet = CreateReturnStringObject(pszBuffer, lstrlen(pszBuffer));
LocalFree(pszBuffer);
pszBuffer = NULL;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: GetWindowInfo could not alloc buffer");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: GetWindowInfo could not quote return strings");
}
}
SysFreeString(bstrTitle);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: GetWindowInfo could not get title");
}
SysFreeString(bstrURL);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: GetWindowInfo could not get URL");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: GetWindowInfo could not parse parameters");
}
EXITPROC(1, TEXT("WWW_GetWindowInfo=%08X"), hddRet);
return hddRet;
}
//
// WWW_OpenURLNewWindow - navigate to a URL (but make sure to spawn a new window)
//
// NOTE: this code was stolen from IEDDEThread::WWW_OpenURL below
//
HDDEDATA CIEDDEThread::WWW_OpenURLNewWindow(LPTSTR pszParams)
{
HDDEDATA hddRet = 0;
LPTSTR pszUrl, pszFile;
ENTERPROC(1, TEXT("WWW_OpenURLNewWindow(pszParams=>%s<)"), pszParams);
if (*pszParams == TEXT('\0') || *pszParams == TEXT('*'))
{
// An empty string is a NOOP.
}
else if (ParseQString(&pszParams, &pszUrl) &&
ParseQString(&pszParams, &pszFile))
{
// null hwnd & bLaunchNewWindow = TRUE means "launch a new window",
// which is exactly what we want to do in the WWW_OpenURLNewWindow case
hddRet = DoNavigate(pszUrl, NULL, TRUE);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: WWW_OpenURLNewWindow could not parse parameters");
}
EXITPROC(1, TEXT("WWW_OpenURL=%08X"), hddRet);
return hddRet;
}
//
// WWW_OpenURL - navigate to a URL
//
// Parameters:
// qcsURL - url to navigate to
// qcsSaveFile - [optional] file to save contents in
// dwWindowID - Window ID to perform navigation
// dwFlags - flags for navigation
// qcsPostFormData - [optional] form data to post to URL
// qcsPostMIMEType - [optional] mime type for form data
// csProgressServer - [optional] DDE server to get progress updates
//
// Returns:
// dwWindowID - window which is doing the work
//
HDDEDATA CIEDDEThread::WWW_OpenURL(LPTSTR pszParams)
{
HDDEDATA hddRet = 0;
LPTSTR pszUrl, pszFile;
WINITEM wi;
ENTERPROC(1, TEXT("WWW_OpenURL(pszParams=>%s<)"), pszParams);
if (*pszParams == TEXT('\0') || *pszParams == TEXT('*'))
{
// An empty string is a NOOP. Needed for NT #291766
}
else if (ParseQString(&pszParams, &pszUrl) &&
ParseQString(&pszParams, &pszFile))
{
//
// APPCOMPAT - a missing hwnd parameter implies -1.
//
if (!ParseWinitem(&pszParams, &wi))
{
TraceMsg(TF_WARNING, "IEDDE: Some bozo isn't giving the required hwnd parameter to WWW_OpenURL, assuming -1");
wi.hwnd = (HWND)-1;
}
#ifdef DEBUG
DWORD dwFlags;
if (!ParseNumber(&pszParams, &dwFlags))
{
TraceMsg(TF_WARNING, "IEDDE: Some bozo isn't giving the required dwFlags parameter to WWW_OpenURL");
}
#endif
hddRet = DoNavigate(pszUrl, wi.hwnd, FALSE);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: OpenURL could not parse parameters");
}
EXITPROC(1, TEXT("WWW_OpenURL=%08X"), hddRet);
return hddRet;
}
//
// WWW_ShowFile - navigate to a file
//
// Parameters:
// qcsFilename - file to load
// qcsPostMIMEType - [optional] mime type for form data
// dwWindowID - Window ID to perform navigation
// qcsURL - URL of the same document
//
// Returns:
// dwWindowID - window which is doing the work
//
HDDEDATA CIEDDEThread::WWW_ShowFile(LPTSTR pszParams)
{
HDDEDATA hddRet = 0;
LPTSTR pszFilename, pszMIMEType;
WINITEM wi;
ENTERPROC(1, TEXT("WWW_ShowFile(pszParams=>%s<)"), pszParams);
if (ParseQString(&pszParams, &pszFilename) && pszFilename[0])
{
if (!ParseQString(&pszParams, &pszMIMEType) || !pszMIMEType[0])
{
TraceMsg(TF_WARNING, "IEDDE: Some bozo isn't giving the required MIMEType parameter to WWW_ShowFile");
}
if (!ParseWinitem(&pszParams, &wi))
{
TraceMsg(TF_WARNING, "IEDDE: Some bozo isn't giving the required dwWindowID parameter to WWW_ShowFile, assuming -1");
wi.hwnd = (HWND)-1;
}
#ifdef DEBUG
LPTSTR pszURL;
if (!ParseQString(&pszParams, &pszURL) || !pszURL[0])
{
TraceMsg(TF_WARNING, "IEDDE: Some bozo isn't giving the required szURL parameter to WWW_ShowFile");
}
#endif
hddRet = DoNavigate(pszFilename, wi.hwnd, FALSE);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: ShowFile could not parse parameters");
}
EXITPROC(1, TEXT("WWW_ShowFile=%08X"), hddRet);
return hddRet;
}
//
// DoNavigate - navigate to a location
//
HDDEDATA CIEDDEThread::DoNavigate(LPTSTR pszLocation, HWND hwnd, BOOL bLaunchNewWindow)
{
HDDEDATA hddRet = 0;
HRESULT hr = S_OK;
TCHAR szParsedPath[MAX_URL_STRING+1];
DWORD cchParsedPath = ARRAYSIZE(szParsedPath);
ENTERPROC(2, TEXT("DoNavigate(pszLocation=>%s<,hwnd=%08X)"), pszLocation, hwnd);
//
// Convert URL from outside format to internal format.
//
if (ParseURLFromOutsideSource(pszLocation, szParsedPath, &cchParsedPath, NULL))
{
pszLocation = szParsedPath;
}
//
// In the case of a file:// URL, convert the location to a path.
//
cchParsedPath = ARRAYSIZE(szParsedPath);
if (IsFileUrlW(pszLocation) && SUCCEEDED(PathCreateFromUrl(pszLocation, szParsedPath, &cchParsedPath, 0)))
{
pszLocation = szParsedPath;
}
LPWSTR pwszPath;
pwszPath = pszLocation;
if (SUCCEEDED(hr))
{
hr = CDDEAuto_Navigate(pwszPath, &hwnd, bLaunchNewWindow ? 1 : 0);
}
DWORD dwServicingWindow = SUCCEEDED(hr) ? -2 : -3;
hddRet = CREATE_HDD(dwServicingWindow);
EXITPROC(2, TEXT("DoNavigate=%08X"), hddRet);
return hddRet;
}
//
// WWW_Activate - activate a browser window
//
// Parameters:
// dwWindowID - Window ID to activate
// dwFlags - should always zero
//
// Returns:
// dwWindowID - window ID that got activated
//
HDDEDATA CIEDDEThread::WWW_Activate(LPTSTR pszParams)
{
HDDEDATA hddRet = 0;
WINITEM wi;
ENTERPROC(1, TEXT("WWW_Activate(pszParams=>%s<)"), pszParams);
if (ParseWinitem(&pszParams, &wi) &&
wi.dwWindowID != 0)
{
#ifdef DEBUG
DWORD dwFlags;
if (ParseNumber(&pszParams, &dwFlags))
{
//
// Netscape spec says this should always be zero.
//
ASSERT(dwFlags == 0);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: Some bozo isn't giving the required dwFlags parameter to WWW_Activate");
}
#endif
//
// dwWindowID of -1 means use the active window.
//
if (wi.dwWindowID == -1)
{
HWND hwnd;
CDDEAuto_get_HWND((long *)&hwnd);
if (hwnd)
{
if (g_pIEDDE->GetWinitemFromHwnd(hwnd, &wi) == FALSE)
{
wi.dwWindowID = (DWORD)-1;
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: Activate could not find an active window");
}
}
//
// Activate the window.
//
if (wi.dwWindowID != -1)
{
if ((GetForegroundWindow() == wi.hwnd) || (SetForegroundWindow(wi.hwnd)))
{
if (IsIconic(wi.hwnd))
{
ShowWindow(wi.hwnd, SW_RESTORE);
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: Activate could not set foreground window");
}
hddRet = CREATE_HDD(wi.dwWindowID);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: Activate could not find a browser window to activate");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: Activate could not parse parameters");
}
EXITPROC(1, TEXT("WWW_Activate=%08X"), hddRet);
return hddRet;
}
//
// WWW_Exit - close all browser windows
//
// Parameters:
// none
//
// Returns:
// none
//
HDDEDATA CIEDDEThread::WWW_Exit(LPTSTR pszParams)
{
HDDEDATA hddRet = 0;
ENTERPROC(1, TEXT("WWW_Exit(pszParams=>%s<)"), pszParams);
CDDEAuto_Exit();
EXITPROC(1, TEXT("WWW_Exit=%08X"), hddRet);
return hddRet;
}
//
// WWW_RegisterURLEcho - register a server for URL change notifications
//
// Parameters:
// qcsServer - the DDE server to get notifications
//
// Returns:
// fSuccess
//
HDDEDATA CIEDDEThread::WWW_RegisterURLEcho(LPTSTR pszParams)
{
HDDEDATA hddRet = 0;
BOOL fSuccess = FALSE;
LPTSTR pszServer;
ENTERPROC(1, TEXT("WWW_RegisterURLEcho(pszParams=>%s<)"), pszParams);
if (ParseQString(&pszParams, &pszServer) && pszServer[0])
{
LPTSTR pszServerCopy = StrDup(pszServer);
if (pszServerCopy)
{
if (g_pIEDDE->AddUrlEcho(pszServerCopy))
{
fSuccess = TRUE;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: RegisterURLEcho could not add an URLEcho");
}
if (!fSuccess)
{
LocalFree(pszServerCopy);
pszServerCopy = NULL;
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: RegisterURLEcho could not dup a string");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: RegisterURLEcho could not parse parameters");
}
hddRet = CREATE_HDD(fSuccess);
EXITPROC(1, TEXT("WWW_RegisterURLEcho=%08X"), hddRet);
return hddRet;
}
//
// WWW_UnregisterURLEcho - unregister a DDE server
//
// Parameters:
// qcsServer - the DDE server to stop getting notifications
//
// Returns:
// fSuccess
//
HDDEDATA CIEDDEThread::WWW_UnregisterURLEcho(LPTSTR pszParams)
{
HDDEDATA hddRet = 0;
BOOL fSuccess = FALSE;
LPTSTR pszServer;
ENTERPROC(1, TEXT("WWW_UnregisterURLEcho(pszParams=>%s<)"), pszParams);
if (ParseQString(&pszParams, &pszServer) && pszServer[0])
{
if (g_pIEDDE->RemoveUrlEcho(pszServer))
{
fSuccess = TRUE;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: UnregisterURLEcho could not find the server");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: UnregisterURLEcho could not parse parameters");
}
hddRet = CREATE_HDD(fSuccess);
EXITPROC(1, TEXT("WWW_UnregisterURLEcho=%08X"), hddRet);
return hddRet;
}
//
// WWW_RegisterProtocol - register a server for handling a protocol
//
// Parameters:
// qcsServer - the DDE server to handle URLs
// qcsProtocol - the protocol to handle
//
// Returns:
// fSuccess - this is the first server to register the protocol
//
HDDEDATA CIEDDEThread::WWW_RegisterProtocol(LPTSTR pszParams)
{
HDDEDATA hddRet = 0;
BOOL fSuccess = FALSE;
LPTSTR pszServer, pszProtocol;
ENTERPROC(1, TEXT("WWW_RegisterProtocol(pszParams=>%s<)"), pszParams);
if (ParseQString(&pszParams, &pszServer) && pszServer[0] &&
ParseQString(&pszParams, &pszProtocol) && pszProtocol[0])
{
if (g_pIEDDE->AddProtocolHandler(pszServer, pszProtocol))
{
fSuccess = TRUE;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: RegisterProtocol unable to register");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: RegisterProtocol could not parse parameters");
}
hddRet = CREATE_HDD(fSuccess);
EXITPROC(1, TEXT("WWW_RegisterProtocol=%08X"), hddRet);
return hddRet;
}
//
// WWW_UnregisterProtocol - unregister a server handling a protocol
//
// Parameters:
// qcsServer - the DDE server which is handling URLs
// qcsProtocol - the protocol getting handled
//
// Returns:
// fSuccess - this server was registered, but now isn't
//
HDDEDATA CIEDDEThread::WWW_UnregisterProtocol(LPTSTR pszParams)
{
HDDEDATA hddRet = 0;
BOOL fSuccess = FALSE;
LPTSTR pszServer, pszProtocol;
ENTERPROC(1, TEXT("WWW_UnregisterProtocol(pszParams=>%s<)"), pszParams);
if (ParseQString(&pszParams, &pszServer) && pszServer[0] &&
ParseQString(&pszParams, &pszProtocol) && pszProtocol[0])
{
if (g_pIEDDE->RemoveProtocolHandler(pszServer, pszProtocol))
{
fSuccess = TRUE;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: UnregisterProtocol unable to unregister");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: UnregisterProtocol could not parse parameters");
}
hddRet = CREATE_HDD(fSuccess);
EXITPROC(1, TEXT("WWW_UnregisterProtocol=%08X"), hddRet);
return hddRet;
}
//
// WWW_ListWindows - Get a list of DDE supported browser window IDs
//
// Parameters:
// none
//
// Returns:
// pdwWindowID (terminated with 0)
//
HDDEDATA CIEDDEThread::WWW_ListWindows(LPTSTR pszParams)
{
HDDEDATA hddRet = 0;
ENTERPROC(1, TEXT("WWW_ListWindows(pszParams=>%s<)"), pszParams);
ENTER_IEDDE_CRIT;
DWORD cbAlloc, *pdwWindowID;
int cWindows = 0;
HDSA hdsaWinitem = g_pIEDDE->GetHdsaWinitem();
if (hdsaWinitem)
{
cWindows = DSA_GetItemCount(hdsaWinitem);
}
//
// Note: we are following the Netscape spec (null terminated pdw) here,
// whereas IE3 followed the Spyglass spec (pdw[0] = count of windows).
//
cbAlloc = (cWindows + 1) * SIZEOF(DWORD);
pdwWindowID = (DWORD *)LocalAlloc(LPTR, cbAlloc);
if (pdwWindowID)
{
DWORD *pdw;
pdw = pdwWindowID;
for (int i=0; i<cWindows; i++)
{
WINITEM wi;
int iResult = DSA_GetItem(hdsaWinitem, i, &wi);
if (iResult != -1)
{
*pdw++ = wi.dwWindowID;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: ListWindows could not get a DSA item");
}
}
hddRet = CreateReturnObject(pdwWindowID, cbAlloc);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: ListWindows could not allocate a window list");
}
LEAVE_IEDDE_CRIT;
EXITPROC(1, TEXT("WWW_ListWindows=%08X"), hddRet);
return hddRet;
}
//
// MakeQuotedString - wrap a string in " marks, escaping internal "s as \"
//
BOOL CIEDDEThread::MakeQuotedString(LPCTSTR pszInput, LPTSTR pszOutput, int cchOutput)
{
BOOL fRet = FALSE;
ENTERPROC(2, TEXT("MakeQuotedString(pszInput=>%s<,pszOutput=%08X,cchOutput=%08X)"), pszInput, pszOutput, cchOutput);
if (cchOutput < 3)
{
TraceMsg(TF_WARNING, "IEDDE: MakeQuotedString has no room for minimal quoted string");
}
else if ((pszInput == NULL) || (*pszInput == TEXT('\0')))
{
StrCpyN(pszOutput, TEXT("\"\""), cchOutput);
fRet = TRUE;
}
else
{
//
// Copy first quote mark.
//
*pszOutput++ = TEXT('"');
cchOutput--;
//
// Copy pszInput, escaping quote marks and making
// sure to leave room for final quote and NULL.
//
while ((cchOutput > 2) && (*pszInput))
{
if (*pszInput == TEXT('"'))
{
*pszOutput++ = TEXT('\\');
cchOutput--;
}
*pszOutput++ = *pszInput++;
cchOutput--;
}
//
// Copy final quote and NULL if we're done and there is room.
//
if ((*pszInput == TEXT('\0')) && (cchOutput >= 2))
{
StrCpyN(pszOutput, TEXT("\""), cchOutput);
fRet = TRUE;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: MakeQuotedString ran out of room in output buffer");
}
}
EXITPROC(2, TEXT("MakeQuotedString=%d"), fRet);
return fRet;
}
#undef CIEDDEThread
//
// There is one global CIEDDE object per process.
// It maintains the global information, such as
// the list of all browsers & what threads they are on,
// and the list of all apps who have registered an URL Echo.
//
// Its methods consist of these categories:
// the DDE callback function
// an internal handler for each exposed IEDDE_ function
// database (hdsa, hdpa) access and manipulation functions
//
// This object creates and destroys CIEDDEThread objects
// (at NewWindow and WindowDestroyed time) and also initializes /
// uninitializes DDE services on a per thread (not per hwnd!) basis.
//
//
// DdeCallback - DDE callback function for IEDDE.
//
#define DDETYPESTR(x) (x == XTYP_REQUEST ? TEXT("Request") : \
(x == XTYP_POKE ? TEXT("Poke") : \
(x == XTYP_EXECUTE ? TEXT("Execute") : \
(x == XTYP_CONNECT ? TEXT("Connect") : TEXT("Unknown")))))
HDDEDATA CIEDDE::DdeCallback(UINT dwType, UINT dwFmt, HCONV hconv, HSZ hsz1, HSZ hsz2, HDDEDATA hdd, DWORD dwData1, DWORD dwData2)
{
HDDEDATA hddRet = 0;
ENTERPROC(2, TEXT("DdeCallback(dwType=%08X(%s),dwFmt=%d,hconv=%d,hsz1=%08X,hsz2=%08X,hdd=%08X,dwData1=%08X,dwData2=%08X)"),
dwType, DDETYPESTR(dwType), dwFmt, hconv, hsz1, hsz2, hdd, dwData1, dwData2);
WINITEM wi;
switch (dwType)
{
case XTYP_REQUEST:
case XTYP_POKE:
if (g_pIEDDE->_GetWinitemFromThread(GetCurrentThreadId(), &wi))
{
hddRet = wi.pidt->OnRequestPoke(hsz1, hsz2);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: DdeCallback unable to get thread info on request / poke");
}
break;
case XTYP_EXECUTE:
if (g_pIEDDE->_GetWinitemFromThread(GetCurrentThreadId(), &wi))
{
hddRet = wi.pidt->OnExecute(hsz1, hdd);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: DdeCallback unable to get thread info on execute");
}
break;
case XTYP_CONNECT:
if (g_pIEDDE->_GetWinitemFromThread(GetCurrentThreadId(), &wi))
{
DDETHREADINFO dti;
wi.pidt->GetDdeThreadInfo(&dti);
hddRet = (HDDEDATA)(hsz2 == dti.hszService);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: DdeCallback unable to get thread info on connect");
}
break;
case XTYP_ADVREQ:
case XTYP_ADVSTOP:
hddRet = DDE_FNOTPROCESSED;
break;
}
EXITPROC(2, TEXT("DdeCallback=%08X"), hddRet);
return hddRet;
}
//
// SendDDEMessageHsz - handle based wrapper for doing one DDE client transaction
//
HDDEDATA CIEDDE::_SendDDEMessageHsz(DWORD dwDDEInst, HSZ hszApp, HSZ hszTopic, HSZ hszMessage, UINT wType)
{
HDDEDATA hddRet = 0;
ENTERPROC(2, TEXT("_SendDDEMessageHsz(dwDDEInst=%08X,hszApp=%08X,hszTopic=%08X,hszMessage=%08X,wType=%d)"), dwDDEInst, hszApp, hszTopic, hszMessage, wType);
if (hszApp && hszTopic)
{
HCONV hconv;
hconv = DdeConnect(dwDDEInst, hszApp, hszTopic, NULL);
if (hconv)
{
hddRet = DdeClientTransaction(NULL, 0, hconv, hszMessage, CF_TEXT, wType, TEN_SECONDS, NULL);
DdeDisconnect(hconv);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _SendDDEMessageHsz could not connect to app");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _SendDDEMessageHsz is missing either App or Topic");
}
EXITPROC(2, TEXT("_SendDDEMessageHsz=%08X"), hddRet);
return hddRet;
}
//
// SendDDEMessageSz - string based wrapper for doing one DDE client transaction
//
HDDEDATA CIEDDE::_SendDDEMessageSz(DWORD dwDDEInst, LPCTSTR pszApp, LPCTSTR pszTopic, LPCTSTR pszMessage, UINT wType)
{
HDDEDATA hddRet = 0;
ENTERPROC(2, TEXT("_SendDDEMessageSz(dwDDEInst=%08X,pszApp=>%s<,pszTopic=>%s<,pszMessage=>%s<,wType=%d)"), dwDDEInst, pszApp, pszTopic, pszMessage, wType);
HSZ hszApp = DdeCreateStringHandle(dwDDEInst, pszApp, CP_WINNEUTRAL);
if (hszApp)
{
HSZ hszTopic = DdeCreateStringHandle(dwDDEInst, pszTopic, CP_WINNEUTRAL);
if (hszTopic)
{
HSZ hszMessage = DdeCreateStringHandle(dwDDEInst, pszMessage, CP_WINNEUTRAL);
if (hszMessage)
{
hddRet = _SendDDEMessageHsz(dwDDEInst, hszApp, hszTopic, hszMessage, wType);
DdeFreeStringHandle(dwDDEInst, hszMessage);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _SendDDEMessageSz could not convert message");
}
DdeFreeStringHandle(dwDDEInst, hszTopic);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _SendDDEMessageSz could not convert topic");
}
DdeFreeStringHandle(dwDDEInst, hszApp);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _SendDDEMessageSz could not convert app");
}
EXITPROC(2, TEXT("_SendDDEMessageSz=%08X"), hddRet);
return hddRet;
}
//
// Initialize - called when ready to start IEDDE server
//
BOOL CIEDDE::_Initialize(void)
{
BOOL fSuccess = TRUE;
ENTERPROC(2, TEXT("_Initialize()"));
ASSERT(_fCSInitialized == FALSE);
InitializeCriticalSection(&_csIEDDE);
_fCSInitialized = TRUE;
EXITPROC(2, TEXT("_Initialize=%d"), fSuccess);
return fSuccess;
}
//
// _DestroyWinitem - DSA callback to partially free the contents of a WINITEM*
// In practice this should never get called, the hdsaWinItem list should be
// empty at uninit time.
//
int CIEDDE::_DestroyWinitem(LPVOID p1, LPVOID p2)
{
WINITEM *pwi = (WINITEM *)p1;
ASSERT(IS_VALID_READ_PTR(pwi, WINITEM));
ASSERT(IS_VALID_READ_PTR(pwi->pidt, CIEDDEThread));
//
// It would be good to unregister the DDE server at this point,
// but we'd need to be on its thread to do it.
//
delete pwi->pidt;
return 1;
}
//
// _DestroyProtocol - DSA callback to free the contents of a PROTOCOLREG*
//
int CIEDDE::_DestroyProtocol(LPVOID p1, LPVOID p2)
{
PROTOCOLREG *pr = (PROTOCOLREG *)p1;
ASSERT(IS_VALID_READ_PTR(pr, PROTOCOLREG));
LocalFree(pr->pszProtocol);
pr->pszProtocol = NULL;
LocalFree(pr->pszServer);
pr->pszServer = NULL;
return 1;
}
//
// _DestroyUrlEcho - DPA callback to free allocated memory
//
int CIEDDE::_DestroyUrlEcho(LPVOID p1, LPVOID p2)
{
ASSERT(IS_VALID_STRING_PTR((LPTSTR)p1, -1));
LocalFree(p1);
p1 = NULL;
return 1;
}
//
// Uninitialize - called when ready to stop IEDDE server
//
void CIEDDE::_Uninitialize(void)
{
ENTERPROC(2, TEXT("_Uninitialize()"));
_fAutomationReady = FALSE;
if (_hdsaWinitem)
{
if (DSA_GetItemCount(_hdsaWinitem))
{
//ASSERT(DSA_GetItemCount(_hdsaWinitem)==0);
TraceMsg(TF_ERROR, "IEDDE: Browser windows still open on uninitialize");
}
DSA_DestroyCallback(_hdsaWinitem, _DestroyWinitem, 0);
_hdsaWinitem = NULL;
}
if (_hdsaProtocolHandler)
{
DSA_DestroyCallback(_hdsaProtocolHandler, _DestroyProtocol, 0);
_hdsaProtocolHandler = NULL;
}
if (_hdpaUrlEcho)
{
DPA_DestroyCallback(_hdpaUrlEcho, _DestroyUrlEcho, 0);
_hdpaUrlEcho = NULL;
}
if (_fCSInitialized)
{
DeleteCriticalSection(&_csIEDDE);
}
EXITPROC(2, TEXT("_Uninitialize!"));
}
void CIEDDE::SetDelayedExecute(LPCTSTR pszTopic, LPCTSTR pszParams)
{
_dwThreadID = GetCurrentThreadId();
Str_SetPtr(&_pszTopic, pszTopic);
Str_SetPtr(&_pszParams, pszParams);
}
void CIEDDE::RunDelayedExecute()
{
if (_pszTopic && _pszParams)
{
WINITEM wi;
if (_GetWinitemFromThread(_dwThreadID, &wi) && wi.pidt)
{
HDDEDATA h = wi.pidt->CallTopic(XTYP_EXECUTE, _pszTopic, _pszParams);
DdeFreeDataHandle(h);
}
}
Str_SetPtr(&_pszTopic, NULL);
Str_SetPtr(&_pszParams, NULL);
}
//
// _AutomationStarted - called when automation support can be called
//
void CIEDDE::_AutomationStarted(void)
{
ENTERPROC(1, TEXT("_AutomationStarted()"));
if (!_fAutomationReady && _pszTopic && _pszParams)
{
WINITEM wi;
if (_GetWinitemFromThread(_dwThreadID, &wi) && wi.pidt)
{
PostMessage(wi.hwnd, WMC_DELAYEDDDEEXEC, 0, 0);
}
}
_fAutomationReady = TRUE;
EXITPROC(1, TEXT("_AutomationStarted!"));
}
//
// _BeforeNavigate - called before a navigation occurs.
//
HRESULT CIEDDE::_BeforeNavigate(LPCTSTR pszURL, BOOL *pfProcessed)
{
ENTERPROC(1, TEXT("_BeforeNavigate(pszURL=>%s<,pfProcessed=%08X)"), pszURL, pfProcessed);
SHSTR shstrMsg;
HRESULT hr = S_OK;
int cProtocols = 0;
ENTER_IEDDE_CRIT;
if (_hdsaProtocolHandler)
{
cProtocols = DSA_GetItemCount(_hdsaProtocolHandler);
}
LEAVE_IEDDE_CRIT;
if (cProtocols)
{
DDETHREADINFO dti;
if (_GetDtiFromThread(GetCurrentThreadId(), &dti))
{
PARSEDURL pu;
pu.cbSize = SIZEOF(pu);
if (SUCCEEDED(ParseURL(pszURL, &pu)))
{
int i;
for (i=0; i<cProtocols; i++)
{
PROTOCOLREG pr;
ENTER_IEDDE_CRIT;
int iResult = DSA_GetItem(_hdsaProtocolHandler, i, &pr);
LEAVE_IEDDE_CRIT;
if (iResult != -1)
{
//
// Check to see if the protocol to navigate
// matches one of our registered protocols.
// We do a case insensitive compare. Note
// that:
//
// (1) ParseURL does not null terminate the
// pu.pszProtocol (its length is stored
// in pu.cchProtocol).
//
// (2) pu.pszProtocol is a LPCTSTR so we
// can't modify the pszProtocol ourselves.
//
// (3) There is no win32 lstrncmpi() API.
//
// Therefore in order to do a case insensitive
// compare we must copy the pu.pszProtocol into
// a writable buffer at some point.
//
if (lstrlen(pr.pszProtocol) == (int)pu.cchProtocol)
{
shstrMsg.SetStr(pu.pszProtocol, pu.cchProtocol);
if (StrCmpI(pr.pszProtocol, shstrMsg) == 0)
{
shstrMsg.SetStr(TEXT("\""));
shstrMsg.Append(pszURL);
shstrMsg.Append(TEXT("\",,-1,0,,,,"));
if (_SendDDEMessageSz(dti.dwDDEInst, pr.pszServer, c_szWWWOpenURL, shstrMsg, XTYP_REQUEST))
{
if (pfProcessed)
{
*pfProcessed = TRUE;
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _BeforeNavigate could not DDE to protocol handler");
}
break;
}
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _BeforeNavigate could not get item from DSA");
}
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _BeforeNavigate could not parse URL");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _BeforeNavigate unable to get thread info, can't use DDE");
}
}
EXITPROC(1, TEXT("_BeforeNavigate=%08X"), hr);
return hr;
}
//
// _AfterNavigate - called after a navigation occurs
//
HRESULT CIEDDE::_AfterNavigate(LPCTSTR pszURL, HWND hwnd)
{
ENTERPROC(1, TEXT("_AfterNavigate(pszURL=>%s<,hwnd=%08X)"), pszURL, hwnd);
int cURLHooks = 0;
SHSTR shstrMsg;
HRESULT hr = S_OK;
ENTER_IEDDE_CRIT;
if (_hdpaUrlEcho)
{
cURLHooks = DPA_GetPtrCount(_hdpaUrlEcho);
}
LEAVE_IEDDE_CRIT;
if (cURLHooks)
{
SHSTR shstrMime;
// (mattsq 1-97)
// this is a temporary lie - it should be fixed to use the real mimetype
// with something like:
// GetMimeTypeFromUrl(pszURL, shstrMime);
// talk to URLMON people
shstrMime.SetStr(TEXT("text/html"));
DDETHREADINFO dti={0};
WINITEM wi;
DWORD dwWindowID;
if (GetWinitemFromHwnd(hwnd, &wi))
{
dwWindowID = wi.dwWindowID;
wi.pidt->GetDdeThreadInfo(&dti);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _AfterNavigate unable to find browser window ID, using -1");
dwWindowID = (DWORD)-1;
WINITEM wiThread;
if (_GetWinitemFromThread(GetCurrentThreadId(), &wiThread))
{
ASSERT(wiThread.pidt);
wiThread.pidt->GetDdeThreadInfo(&dti);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _AfterNavigate unable to find DDE thread info");
}
}
if (dti.dwDDEInst)
{
HSZ hszTopic = DdeCreateStringHandle(dti.dwDDEInst, c_szWWWUrlEcho, CP_WINNEUTRAL);
if (hszTopic)
{
TCHAR szFinish[16];
shstrMsg.SetStr(TEXT("\"")); // Quote
shstrMsg.Append(pszURL); // URL
shstrMsg.Append(TEXT("\",\"")); // Quote Comma Quote
shstrMsg.Append(shstrMime); // Mime
wnsprintf(szFinish, ARRAYSIZE(szFinish), TEXT("\",%d"), dwWindowID); //
shstrMsg.Append(szFinish); // Quote Comma dwWindowID NULL
HSZ hszMsg = DdeCreateStringHandle(dti.dwDDEInst, shstrMsg, CP_WINNEUTRAL);
if (hszMsg)
{
//
// Enumerate in reverse order because calling a hook may destroy it.
//
for (int i=cURLHooks-1; i>=0; --i)
{
ENTER_IEDDE_CRIT;
LPTSTR pszService = (LPTSTR)DPA_GetPtr(_hdpaUrlEcho, i);
LEAVE_IEDDE_CRIT;
if (pszService != NULL)
{
HSZ hszService = DdeCreateStringHandle(dti.dwDDEInst, pszService, CP_WINNEUTRAL);
if (hszService)
{
if (_SendDDEMessageHsz(dti.dwDDEInst, hszService, hszTopic, hszMsg, XTYP_POKE) == 0)
{
TraceMsg(TF_WARNING, "IEDDE: _AfterNavigate could not DDE to URLHook handler");
}
DdeFreeStringHandle(dti.dwDDEInst, hszService);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _AfterNavigate unable to create hszService");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _AfterNavigate unable to enumerate an URL hook");
}
}
DdeFreeStringHandle(dti.dwDDEInst, hszMsg);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _AfterNavigate unable to create hszMsg");
}
DdeFreeStringHandle(dti.dwDDEInst, hszTopic);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _AfterNavigate unable to create hszTopic");
}
}
}
EXITPROC(1, TEXT("_AfterNavigate=%08X"), hr);
return hr;
}
//
// GetWinitemFromHwnd - return the winitem associated with an hwnd
//
BOOL CIEDDE::GetWinitemFromHwnd(HWND hwnd, WINITEM *pwi)
{
BOOL fSuccess = FALSE;
ENTERPROC(2, TEXT("GetWinitemFromHwnd(hwnd=%08X,pwi=%08X)"), hwnd, pwi);
ENTER_IEDDE_CRIT;
if (_hdsaWinitem)
{
for (int i=0; i<DSA_GetItemCount(_hdsaWinitem); i++)
{
WINITEM wi;
if (DSA_GetItem(_hdsaWinitem, i, &wi) != -1)
{
if (wi.hwnd == hwnd)
{
*pwi = wi;
fSuccess = TRUE;
break;
}
}
}
}
LEAVE_IEDDE_CRIT;
EXITPROC(2, TEXT("GetWinitemFromHwnd=%d"), fSuccess);
return fSuccess;
}
//
// GetWinitemFromWindowID - return the winitem associated with a window ID
//
BOOL CIEDDE::GetWinitemFromWindowID(DWORD dwWindowID, WINITEM *pwi)
{
BOOL fSuccess = FALSE;
ENTERPROC(3, TEXT("GetWinitemFromWindowID(dwWindowID=%08X,pwi=%08X)"), dwWindowID, pwi);
ENTER_IEDDE_CRIT;
if (_hdsaWinitem)
{
for (int i=0; i<DSA_GetItemCount(_hdsaWinitem); i++)
{
WINITEM wi;
if (DSA_GetItem(_hdsaWinitem, i, &wi) != -1)
{
if (wi.dwWindowID == dwWindowID)
{
*pwi = wi;
fSuccess = TRUE;
break;
}
}
}
}
LEAVE_IEDDE_CRIT;
EXITPROC(2, TEXT("GetWinitemFromWindowID=%d"), fSuccess);
return fSuccess;
}
//
// _GetWinitemFromThread - return the first winitem associated with a thread
//
BOOL CIEDDE::_GetWinitemFromThread(DWORD dwThreadID, WINITEM *pwi)
{
BOOL fSuccess = FALSE;
ENTERPROC(2, TEXT("_GetWinitemFromThread(dwThreadID=%08X,pwi=%08X)"), dwThreadID, pwi);
ENTER_IEDDE_CRIT;
if (_hdsaWinitem)
{
for (int i=0; i<DSA_GetItemCount(_hdsaWinitem); i++)
{
WINITEM wi;
if (DSA_GetItem(_hdsaWinitem, i, &wi) != -1)
{
if (wi.dwThreadID == dwThreadID)
{
*pwi = wi;
fSuccess = TRUE;
break;
}
}
}
}
LEAVE_IEDDE_CRIT;
EXITPROC(2, TEXT("_GetWinitemFromThread=%d"), fSuccess);
return fSuccess;
}
//
// _GetDtiFromThread - return the threadinfo associated with a thread
//
BOOL CIEDDE::_GetDtiFromThread(DWORD dwThreadID, DDETHREADINFO *pdti)
{
BOOL fSuccess = FALSE;
ENTERPROC(2, TEXT("_GetDtiFromThread(dwThreadID=%08X,pdti=%08X)"), dwThreadID, pdti);
ENTER_IEDDE_CRIT;
WINITEM wi;
if (_GetWinitemFromThread(dwThreadID, &wi))
{
wi.pidt->GetDdeThreadInfo(pdti);
fSuccess = TRUE;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _GetDtiFromThread unable to find winitem");
}
LEAVE_IEDDE_CRIT;
EXITPROC(2, TEXT("_GetDtiFromThread=%d"), fSuccess);
return fSuccess;
}
//
// _CreateDdeThreadInfo - Initialize DDE services and names for this thread
//
BOOL CIEDDE::_CreateDdeThreadInfo(DDETHREADINFO *pdti)
{
BOOL fSuccess = FALSE;
ENTERPROC(2, TEXT("_CreateDdeThreadInfo(pdti=%08X)"), pdti);
UINT uiDDE;
DDETHREADINFO dti={0};
//
// Initialize DDEML, register our service.
//
uiDDE = DdeInitialize(&dti.dwDDEInst, (PFNCALLBACK)DdeCallback,
APPCLASS_STANDARD | CBF_FAIL_ADVISES |
CBF_SKIP_REGISTRATIONS | CBF_SKIP_UNREGISTRATIONS, 0);
if (uiDDE == DMLERR_NO_ERROR)
{
dti.hszReturn = DdeCreateStringHandle(dti.dwDDEInst, c_szReturn, CP_WINNEUTRAL);
if (dti.hszReturn)
{
dti.hszService = DdeCreateStringHandle(dti.dwDDEInst, c_szIExplore, CP_WINNEUTRAL);
if (dti.hszService)
{
*pdti = dti;
fSuccess = TRUE;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _CreateDdeThreadInfo unable to convert service");
}
if (!fSuccess)
{
DdeFreeStringHandle(dti.dwDDEInst, dti.hszReturn);
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _CreateDdeThreadInfo unable to convert return");
}
if (!fSuccess)
{
DdeUninitialize(dti.dwDDEInst);
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _CreateDdeThreadInfo unable to init DDE");
}
EXITPROC(2, TEXT("_CreateDdeThreadInfo=%d"), fSuccess);
return fSuccess;
}
//
// _DestroyDdeThreadInfo - Free up any resources in a dti structure.
//
void CIEDDE::_DestroyDdeThreadInfo(DDETHREADINFO *pdti)
{
ENTERPROC(2, TEXT("_DestroyDdeThreadInfo(pdti=%08X)"), pdti);
if (pdti->hddNameService)
{
ASSERT(pdti->hszService);
DdeNameService(pdti->dwDDEInst, pdti->hszService, 0, DNS_UNREGISTER);
pdti->hddNameService = 0;
}
if (pdti->hszService)
{
DdeFreeStringHandle(pdti->dwDDEInst, pdti->hszService);
pdti->hszService = 0;
}
if (pdti->hszReturn)
{
DdeFreeStringHandle(pdti->dwDDEInst, pdti->hszReturn);
pdti->hszReturn = 0;
}
if (pdti->dwDDEInst)
{
DdeUninitialize(pdti->dwDDEInst);
pdti->dwDDEInst = 0;
}
EXITPROC(2, TEXT("_DestroyDdeThreadInfo!"));
return;
}
//
// _AddWinitem - adds a winitem to _hdsaWinitem
//
BOOL CIEDDE::_AddWinitem(WINITEM *pwi)
{
BOOL fSuccess = FALSE;
ENTERPROC(2, TEXT("_AddWinitem(pwi=%08X)"), pwi);
ENTER_IEDDE_CRIT;
if (!_hdsaWinitem)
{
_hdsaWinitem = DSA_Create(SIZEOF(WINITEM), DXA_GROWTH_AMOUNT);
}
if (_hdsaWinitem)
{
if (DSA_AppendItem(_hdsaWinitem, pwi) != -1)
{
fSuccess = TRUE;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _AddWinitem could not append an item");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _AddWinitem could not create hdsa");
}
LEAVE_IEDDE_CRIT;
EXITPROC(2, TEXT("_AddWinitem=%d"), fSuccess);
return fSuccess;
}
//
// _UpdateWinitem - updates a winitem based on the dwWindowID.
//
BOOL CIEDDE::_UpdateWinitem(WINITEM *pwi)
{
BOOL fSuccess = FALSE;
ENTERPROC(2, TEXT("_UpdateWinitem(pwi=%08X)"), pwi);
ENTER_IEDDE_CRIT;
if (_hdsaWinitem)
{
int cItems = DSA_GetItemCount(_hdsaWinitem);
for (int i=0; i<cItems; i++)
{
WINITEM wi;
if (DSA_GetItem(_hdsaWinitem, i, &wi) != -1)
{
if (wi.dwWindowID == pwi->dwWindowID)
{
if (DSA_SetItem(_hdsaWinitem, i, pwi))
{
fSuccess = TRUE;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _UpdateWinitem could not update an item");
}
break;
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _UpdateWinitem could not get an item");
}
}
}
LEAVE_IEDDE_CRIT;
EXITPROC(2, TEXT("_UpdateWinitem=%d"), fSuccess);
return fSuccess;
}
//
// AddUrlEcho - adds an UrlEcho entry to the dpa
//
BOOL CIEDDE::AddUrlEcho(LPCTSTR pszUrlEcho)
{
BOOL fSuccess = FALSE;
ENTERPROC(2, TEXT("AddUrlEcho(pszUrlEcho=>%s<)"), pszUrlEcho);
ENTER_IEDDE_CRIT;
if (!_hdpaUrlEcho)
{
_hdpaUrlEcho = DPA_Create(DXA_GROWTH_AMOUNT);
}
if (_hdpaUrlEcho)
{
if (DPA_AppendPtr(_hdpaUrlEcho, (LPVOID)pszUrlEcho) != -1)
{
fSuccess = TRUE;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: AddUrlEcho unable to append a ptr");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: AddUrlEcho unable to create a dpa");
}
LEAVE_IEDDE_CRIT;
EXITPROC(2, TEXT("AddUrlEcho=%d"), fSuccess);
return fSuccess;
}
//
// RemoveUrlEcho - remove an UrlEcho entry from the dpa
//
BOOL CIEDDE::RemoveUrlEcho(LPCTSTR pszUrlEcho)
{
BOOL fSuccess = FALSE;
ENTERPROC(2, TEXT("RemoveUrlEcho(pszUrlEcho=>%s<)"), pszUrlEcho);
ENTER_IEDDE_CRIT;
if (_hdpaUrlEcho)
{
for (int i=0; i<DPA_GetPtrCount(_hdpaUrlEcho); i++)
{
LPTSTR pszList = (LPTSTR)DPA_GetPtr(_hdpaUrlEcho, i);
if (pszList)
{
if (StrCmpI(pszList, pszUrlEcho) == 0)
{
DPA_DeletePtr(_hdpaUrlEcho, i);
LocalFree((HANDLE)pszList);
pszList = NULL;
fSuccess = TRUE;
break;
}
}
else
{
TraceMsg(TF_ALWAYS, "IEDDE: RemoveUrlEcho unable to get dpa ptr");
}
}
if (!fSuccess)
{
TraceMsg(TF_WARNING, "IEDDE: RemoveUrlEcho unable to find server");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: RemoveUrlEcho unable to find dpa");
}
LEAVE_IEDDE_CRIT;
EXITPROC(2, TEXT("RemoveUrlEcho=%d"), fSuccess);
return fSuccess;
}
//
// AddProtocolHandler - add a PROTOCOLREG entry to the dsa
//
BOOL CIEDDE::AddProtocolHandler(LPCTSTR pszServer, LPCTSTR pszProtocol)
{
BOOL fSuccess = FALSE;
ENTERPROC(2, TEXT("AddProtocolHandler(pszServer=>%s<,pszProtocol=>%s<)"), pszServer, pszProtocol);
ENTER_IEDDE_CRIT;
PROTOCOLREG pr;
//
// First, see if anybody else grabbed the protocol first.
//
BOOL fFoundHandler = FALSE;
if (_hdsaProtocolHandler)
{
for (int i=0; i<DSA_GetItemCount(_hdsaProtocolHandler); i++)
{
if (DSA_GetItem(_hdsaProtocolHandler, i, &pr) != -1)
{
if (StrCmpI(pr.pszProtocol, pszProtocol) == 0)
{
TraceMsg(TF_WARNING, "IEDDE: AddProtocolHandler already has a handler");
fFoundHandler = TRUE;
break;
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: AddProtocolHandler unable to get an item");
}
}
}
if (!fFoundHandler)
{
if (!_hdsaProtocolHandler)
{
_hdsaProtocolHandler = DSA_Create(SIZEOF(PROTOCOLREG), DXA_GROWTH_AMOUNT);
}
if (_hdsaProtocolHandler)
{
pr.pszServer = StrDup(pszServer);
if (pr.pszServer)
{
pr.pszProtocol = StrDup(pszProtocol);
if (pr.pszProtocol)
{
if (DSA_AppendItem(_hdsaProtocolHandler, &pr) != -1)
{
fSuccess = TRUE;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: AddProtocolHandler unable to append to dsa");
}
if (!fSuccess)
{
LocalFree((HANDLE)pr.pszProtocol);
pr.pszProtocol = NULL;
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: AddProtocolHandler unable to dup protocol");
}
if (!fSuccess)
{
LocalFree((HANDLE)pr.pszServer);
pr.pszServer = NULL;
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: AddProtocolHandler unable to dup server");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: AddProtocolHandler unable to create dsa");
}
}
LEAVE_IEDDE_CRIT;
EXITPROC(2, TEXT("AddProtocolHandler=%d"), fSuccess);
return fSuccess;
}
//
// RemoveProtocolHandler - removes a PROTOCOLREG item from the dsa
//
BOOL CIEDDE::RemoveProtocolHandler(LPCTSTR pszServer, LPCTSTR pszProtocol)
{
BOOL fSuccess = FALSE;
ENTERPROC(2, TEXT("RemoveProtocolHandler(pszServer=>%s<,pszProtocol=>%s<)"), pszServer, pszProtocol);
ENTER_IEDDE_CRIT;
if (_hdsaProtocolHandler)
{
for (int i=0; i<DSA_GetItemCount(_hdsaProtocolHandler); i++)
{
PROTOCOLREG pr;
if (DSA_GetItem(_hdsaProtocolHandler, i, &pr) != -1)
{
if (StrCmpI(pr.pszProtocol, pszProtocol) == 0)
{
if (StrCmpI(pr.pszServer, pszServer) == 0)
{
if (DSA_DeleteItem(_hdsaProtocolHandler, i) != -1)
{
LocalFree((HANDLE)pr.pszServer);
pr.pszServer = NULL;
LocalFree((HANDLE)pr.pszProtocol);
pr.pszProtocol = NULL;
fSuccess = TRUE;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: RemoveProtocolHandler unable to remove item");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: RemoveProtocolHandler says server didn't match");
}
break;
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: RemoveProtocolHandler unable to get item");
}
}
if (!fSuccess)
{
TraceMsg(TF_WARNING, "IEDDE: RemoveProtocolHandler unable to complete mission");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: RemoveProtocolHandler can't find the dsa");
}
LEAVE_IEDDE_CRIT;
EXITPROC(2, TEXT("RemoveProtocolHandler=%d"), fSuccess);
return fSuccess;
}
//
// _DeleteWinitemByHwnd - removes a winitem from _hdsaWinitem
//
BOOL CIEDDE::_DeleteWinitemByHwnd(HWND hwnd, WINITEM *pwi)
{
BOOL fSuccess = FALSE;
ENTERPROC(2, TEXT("_DeleteWinitemByHwnd(hwnd=%08X,pwi=%08X)"), hwnd, pwi);
ENTER_IEDDE_CRIT;
if (_hdsaWinitem)
{
for (int i=0; i<DSA_GetItemCount(_hdsaWinitem); i++)
{
WINITEM wi;
if (DSA_GetItem(_hdsaWinitem, i, &wi) != -1)
{
if (wi.hwnd == hwnd)
{
if (DSA_DeleteItem(_hdsaWinitem, i) != -1)
{
*pwi = wi;
fSuccess = TRUE;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _DeleteWinitemByHwnd could note delete an item");
}
break;
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _DeleteWinitemByHwnd could note get an item");
}
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _DeleteWinitemByHwnd has no _hdsaWinitem");
}
LEAVE_IEDDE_CRIT;
EXITPROC(2, TEXT("_DeleteWinitemByHwnd=%d"), fSuccess);
return fSuccess;
}
//
// _NewWindow - Add a browser window to the internal list
//
BOOL CIEDDE::_NewWindow(HWND hwnd)
{
BOOL fSuccess = FALSE;
ENTERPROC(1, TEXT("NewWindow(hwnd=%08X)"), hwnd);
ASSERT(IS_VALID_HANDLE(hwnd, WND));
ENTER_IEDDE_CRIT;
WINITEM wi;
if (GetWinitemFromHwnd(hwnd, &wi) == FALSE)
{
CIEDDEThread *pidt = new CIEDDEThread();
if (pidt)
{
DDETHREADINFO dti = {0};
DWORD dwThreadID = GetCurrentThreadId();
WINITEM wi;
BOOL fCreatedDTI = FALSE;
if (_GetWinitemFromThread(dwThreadID, &wi))
{
wi.pidt->GetDdeThreadInfo(&dti);
}
else
{
LEAVE_IEDDE_CRIT;
_CreateDdeThreadInfo(&dti);
ENTER_IEDDE_CRIT;
fCreatedDTI = TRUE;
}
if (dti.dwDDEInst)
{
static DWORD dwNextWindowID = 1;
pidt->SetDdeThreadInfo(&dti);
wi.dwThreadID = dwThreadID;
wi.pidt = pidt;
wi.hwnd = hwnd;
wi.dwWindowID = dwNextWindowID++;
if (_AddWinitem(&wi))
{
//
// Now that we have a (partial) winitem in the winitem
// database, we can register our name service. If we
// registered any sooner, there is a risk that an app
// will try to connect to us while we are registering,
// and we will fail the connect because the winitem
// is not in the registry yet.
//
LEAVE_IEDDE_CRIT;
dti.hddNameService = DdeNameService(dti.dwDDEInst, dti.hszService, 0, DNS_REGISTER);
ENTER_IEDDE_CRIT;
//
// Now that we have hddNameService, we can update the
// winitem in the database.
//
if (dti.hddNameService)
{
pidt->SetDdeThreadInfo(&dti);
if (_UpdateWinitem(&wi))
{
fSuccess = TRUE;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _NewWindow unable to update a win item");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _NewWindow unable to register service");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _NewWindow could not append win item");
}
if (!fSuccess && fCreatedDTI)
{
LEAVE_IEDDE_CRIT;
_DestroyDdeThreadInfo(&dti);
ENTER_IEDDE_CRIT;
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _NewWindow could not get/create dde thread info");
}
if (!fSuccess)
{
delete pidt;
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _NewWindow could not create iedde thread object");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _NewWindow says window already registered?!?");
}
LEAVE_IEDDE_CRIT;
EXITPROC(1, TEXT("_NewWindow=%d"), fSuccess);
return fSuccess;
}
//
// _WindowDestroyed - Remove a browser window from the internal list
//
BOOL CIEDDE::_WindowDestroyed(HWND hwnd)
{
BOOL fSuccess = FALSE;
ENTERPROC(1, TEXT("_WindowDestroyed(hwnd=%08X)"), hwnd);
ENTER_IEDDE_CRIT;
WINITEM wi;
if (_DeleteWinitemByHwnd(hwnd, &wi))
{
fSuccess = TRUE;
ASSERT(wi.pidt);
WINITEM wiThread;
if (_GetWinitemFromThread(wi.dwThreadID, &wiThread) == FALSE)
{
if (wi.dwThreadID == GetCurrentThreadId())
{
DDETHREADINFO dti;
wi.pidt->GetDdeThreadInfo(&dti);
// Don't hold onto critical section while doing this...
LEAVE_IEDDE_CRIT;
_DestroyDdeThreadInfo(&dti);
ENTER_IEDDE_CRIT;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _WindowDestroyed called on wrong thread");
}
}
delete wi.pidt;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: _WindowDestroyed could not find hwnd");
}
LEAVE_IEDDE_CRIT;
EXITPROC(1, TEXT("_WindowDestroyed=%d"), fSuccess);
return fSuccess;
}
//
// IEDDE_ functions are those exported for other parts of shdocvw to call.
// They pretty much just call the equivalent function in g_pIEDDE.
//
BOOL IEDDE_Initialize(void)
{
BOOL fRet = FALSE;
ENTERPROC(2, TEXT("IEDDE_Initialize()"));
if (g_pIEDDE == NULL)
{
g_pIEDDE = new CIEDDE;
if (g_pIEDDE)
{
fRet = g_pIEDDE->_Initialize();
}
else
{
TraceMsg(TF_WARNING, "IEDDE: IEDDE_Initialize could not allocate an IEDDE object");
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: IEDDE_Initialize says already initialized");
}
EXITPROC(2, TEXT("IEDDE_Initialize=%d"), fRet);
return fRet;
}
void IEDDE_Uninitialize(void)
{
ENTERPROC(2, TEXT("IEDDE_Uninitialize()"));
if (g_pIEDDE)
{
g_pIEDDE->_Uninitialize();
delete g_pIEDDE;
g_pIEDDE = NULL;
}
else
{
TraceMsg(TF_WARNING, "IEDDE: IEDDE_Uninitialize has no IEDDE object");
}
EXITPROC(2, TEXT("IEDDE_Uninitialize!"));
}
BOOL IEDDE_RunDelayedExecute()
{
if (g_pIEDDE)
{
g_pIEDDE->RunDelayedExecute();
}
else
{
TraceMsg(TF_WARNING, "IEDDE: IEDDE_RunDelayedExecute has no IEDDE object");
}
return TRUE;
}
void IEDDE_AutomationStarted(void)
{
ENTERPROC(2, TEXT("IEDDE_AutomationStarted()"));
if (g_pIEDDE)
{
g_pIEDDE->_AutomationStarted();
}
else
{
TraceMsg(TF_WARNING, "IEDDE: IEDDE_AutomationStarted has no IEDDE object");
}
EXITPROC(2, TEXT("IEDDE_AutomationStarted!"));
}
HRESULT IEDDE_BeforeNavigate(LPCWSTR pwszURL, BOOL *pfCanceled)
{
HRESULT hr = E_FAIL;
ENTERPROC(2, TEXT("IEDDE_BeforeNavigate(pwszURL=%08X,pfCanceled=%08X)"), pwszURL, pfCanceled);
if (g_pIEDDE)
{
LPCTSTR pszURL;
pszURL = pwszURL;
if (pszURL)
{
hr = g_pIEDDE->_BeforeNavigate(pszURL, pfCanceled);
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: IEDDE_BeforeNavigate has no IEDDE object");
}
EXITPROC(2, TEXT("IEDDE_BeforeNavigate=%08X"), hr);
return hr;
}
HRESULT IEDDE_AfterNavigate(LPCWSTR pwszURL, HWND hwnd)
{
HRESULT hr = E_FAIL;
ENTERPROC(2, TEXT("IEDDE_AfterNavigate(pwszURL=%08X,hwnd=%08X)"), pwszURL, hwnd);
if (g_pIEDDE)
{
LPCTSTR pszURL;
pszURL = pwszURL;
if (pszURL)
{
hr = g_pIEDDE->_AfterNavigate(pszURL, hwnd);
}
}
else
{
TraceMsg(TF_WARNING, "IEDDE: IEDDE_AfterNavigate has no IEDDE object");
}
EXITPROC(2, TEXT("IEDDE_AfterNavigate=%08X"), hr);
return hr;
}
BOOL IEDDE_NewWindow(HWND hwnd)
{
BOOL fRet = FALSE;
ENTERPROC(2, TEXT("IEDDE_NewWindow(hwnd=%08X)"), hwnd);
if (g_pIEDDE)
{
fRet = g_pIEDDE->_NewWindow(hwnd);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: IEDDE_NewWindow has no IEDDE object");
}
EXITPROC(2, TEXT("IEDDE_NewWindow=%d"), fRet);
return fRet;
}
BOOL IEDDE_WindowDestroyed(HWND hwnd)
{
BOOL fRet = FALSE;
ENTERPROC(2, TEXT("IEDDE_WindowDestroyed(hwnd=%08X)"), hwnd);
if (g_pIEDDE)
{
fRet = g_pIEDDE->_WindowDestroyed(hwnd);
}
else
{
TraceMsg(TF_WARNING, "IEDDE: IEDDE_WindowDestroyed has no IEDDE object");
}
EXITPROC(2, TEXT("IEDDE_WindowDestroyed=%d"), fRet);
return fRet;
}
#ifdef DEBUG
//
// Move g_dwIEDDETrace into ccshell.ini to prevent recompiles.
//
DWORD g_dwIEDDETrace = 0;
static DWORD g_dwIndent = 0;
static const TCHAR c_szDotDot[] = TEXT("..");
#define MAX_INDENTATION_VALUE 0x10
void EnterProc(DWORD dwTraceLevel, LPTSTR szFmt, ...)
{
TCHAR szOutput[1000];
va_list arglist;
if (dwTraceLevel <= g_dwIEDDETrace)
{
szOutput[0] = TEXT('\0');
for (DWORD i=0; i<g_dwIndent; i++)
{
StrCatBuff(szOutput, c_szDotDot, ARRAYSIZE(szOutput));
}
va_start(arglist, szFmt);
wvnsprintf(szOutput + lstrlen(szOutput), ARRAYSIZE(szOutput) - lstrlen(szOutput), szFmt, arglist);
va_end(arglist);
TraceMsg(TF_ALWAYS, "%s", szOutput);
// This value can get out of hand if EnterProc and ExitProc
// calls do not match. This can trash the stack.
if(g_dwIndent < MAX_INDENTATION_VALUE)
g_dwIndent++;
}
}
void ExitProc(DWORD dwTraceLevel, LPTSTR szFmt, ...)
{
TCHAR szOutput[1000];
va_list arglist;
if (dwTraceLevel <= g_dwIEDDETrace)
{
// This can happen if the EnterProc and
// ExitProc calls do not match.
if(g_dwIndent > 0)
g_dwIndent--;
szOutput[0] = TEXT('\0');
for (DWORD i=0; i<g_dwIndent; i++)
{
StrCatBuff(szOutput, c_szDotDot, ARRAYSIZE(szOutput));
}
va_start(arglist, szFmt);
wvnsprintf(szOutput + lstrlen(szOutput), ARRAYSIZE(szOutput) - lstrlen(szOutput), szFmt, arglist);
va_end(arglist);
TraceMsg(TF_ALWAYS, "%s", szOutput);
}
}
#endif