/* 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%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%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; iGetDdeThreadInfo(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; idwWindowID) { 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%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%s<,pszProtocol=>%s<)"), pszServer, pszProtocol); ENTER_IEDDE_CRIT; if (_hdsaProtocolHandler) { for (int i=0; iGetDdeThreadInfo(&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 0) g_dwIndent--; szOutput[0] = TEXT('\0'); for (DWORD i=0; i