iedde.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 75k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. /* Copyright 1996 Microsoft */
  2. #include "priv.h"
  3. #ifdef DEBUG
  4. #define ENTERPROC EnterProc
  5. #define EXITPROC ExitProc
  6. void EnterProc(DWORD dwTraceLevel, LPTSTR szFmt, ...);
  7. void ExitProc(DWORD dwTraceLevel, LPTSTR szFmt, ...);
  8. extern DWORD g_dwIEDDETrace;
  9. #else
  10. #pragma warning(disable:4002)
  11. #ifndef UNIX
  12. #ifndef CCOVER
  13. #define ENTERPROC()
  14. #define EXITPROC()
  15. #else //CCOVER
  16. // these are needed because of a bug in cl.exe which causes 
  17. // compilation problems with #pragma when a program is preprocessed
  18. // and compiled separately
  19. #define ENTERPROC 1 ? (void) 0 : (void)
  20. #define EXITPROC 1 ? (void) 0 : (void)
  21. #endif // CCOVER
  22. #else
  23. #define ENTERPROC EnterProc
  24. #define EXITPROC ExitProc
  25. inline void EnterProc(DWORD dwTraceLevel, LPTSTR szFmt, ...){}
  26. inline void ExitProc(DWORD dwTraceLevel, LPTSTR szFmt, ...){}
  27. #endif
  28. #endif
  29. //
  30. // Forward reference.
  31. //
  32. class CIEDDEThread;
  33. //
  34. // Stored in _hdsaWinitem
  35. //
  36. typedef struct _tagWinItem
  37. {
  38.     DWORD           dwWindowID;     // Synthetic window ID exposed in IEDDE interfaces
  39.     HWND            hwnd;           // Actual hwnd of browser window
  40.     DWORD           dwThreadID;     // ThreadID for this browser window
  41.     CIEDDEThread    *pidt;          // Thread specific data and methods
  42. } WINITEM;
  43. //
  44. // Stored in _hdsaProtocolHandler
  45. //
  46. typedef struct _tagProtocolReg
  47. {
  48.     LPTSTR  pszProtocol;
  49.     LPTSTR  pszServer;
  50. } PROTOCOLREG;
  51. #define TEN_SECONDS         (10 * 1000)
  52. #define DXA_GROWTH_AMOUNT   (10)
  53. #ifndef UNIX
  54. #define IEXPLORE_STR "IEXPLORE"
  55. #else
  56. #define IEXPLORE_STR "iexplorer"
  57. #endif
  58. static const TCHAR c_szIExplore[] = TEXT(IEXPLORE_STR);
  59. static const TCHAR c_szReturn[] = TEXT("Return");
  60. static const TCHAR c_szWWWOpenURL[] = TEXT("WWW_OpenURL");
  61. static const TCHAR c_szWWWUrlEcho[] = TEXT("WWW_URLEcho");
  62. typedef struct _tagDDETHREADINFO
  63. {
  64.     DWORD       dwDDEInst;
  65.     HSZ         hszService;
  66.     HSZ         hszReturn;
  67.     HDDEDATA    hddNameService;
  68. } DDETHREADINFO;
  69. class CIEDDEThread {
  70. public:
  71.     CIEDDEThread() { };
  72.     ~CIEDDEThread() { };
  73.     void GetDdeThreadInfo(DDETHREADINFO *pdti) { *pdti = _dti; }
  74.     void SetDdeThreadInfo(DDETHREADINFO *pdti) { _dti = *pdti; }
  75.     HDDEDATA OnRequestPoke(HSZ hszTopic, HSZ hszParams);
  76.     HDDEDATA OnExecute(HSZ hszTopic, HDDEDATA hddParams);
  77. protected:
  78.     DDETHREADINFO   _dti;
  79.     HDDEDATA CallTopic(DWORD dwType, LPCTSTR pszTopic, LPTSTR pszParams);
  80.     HDDEDATA DoNavigate(LPTSTR pszLocation, HWND hwnd);
  81.     BOOL MakeQuotedString(LPCTSTR pszInput, LPTSTR pszOutput, int cchOutput);
  82.     HDDEDATA CreateReturnObject(LPVOID p, DWORD cb);
  83.     HDDEDATA CreateReturnStringObject(LPTSTR pszReturnString, DWORD cch);
  84.     BOOL ParseString(LPTSTR *ppsz, LPTSTR *ppszString);
  85.     BOOL ParseQString(LPTSTR *ppsz, LPTSTR *ppszString);
  86.     BOOL ParseNumber(LPTSTR *ppsz, DWORD *pdw);
  87.     BOOL ParseWinitem(LPTSTR *ppsz, WINITEM *pwi);
  88.     HDDEDATA WWW_GetWindowInfo(LPTSTR pszParams);
  89.     HDDEDATA WWW_OpenURL(LPTSTR pszParams);
  90.     HDDEDATA WWW_ShowFile(LPTSTR pszParams);
  91.     HDDEDATA WWW_Activate(LPTSTR pszParams);
  92.     HDDEDATA WWW_Exit(LPTSTR pszParams);
  93.     HDDEDATA WWW_RegisterURLEcho(LPTSTR pszParams);
  94.     HDDEDATA WWW_UnregisterURLEcho(LPTSTR pszParams);
  95.     HDDEDATA WWW_RegisterProtocol(LPTSTR pszParams);
  96.     HDDEDATA WWW_UnregisterProtocol(LPTSTR pszParams);
  97.     HDDEDATA WWW_ListWindows(LPTSTR pszParams);
  98. };
  99. class CIEDDE {
  100. public:
  101.     CIEDDE() { };
  102.     ~CIEDDE() { };
  103.     BOOL IsAutomationReady(void) { return _fAutomationReady; }
  104.     BOOL GetWinitemFromWindowID(DWORD dwWindowID, WINITEM *pwi);
  105.     BOOL GetWinitemFromHwnd(HWND hwnd, WINITEM *pwi);
  106.     BOOL AddUrlEcho(LPCTSTR pszUrlEcho);
  107.     BOOL RemoveUrlEcho(LPCTSTR pszUrlEcho);
  108.     BOOL AddProtocolHandler(LPCTSTR pszServer, LPCTSTR pszProtocol);
  109.     BOOL RemoveProtocolHandler(LPCTSTR pszServer, LPCTSTR pszProtocol);
  110.     HDSA GetHdsaWinitem(void) { return _hdsaWinitem; }
  111.     static HDDEDATA DdeCallback(UINT dwType, UINT dwFmt, HCONV hconv, HSZ hsz1, HSZ hsz2, HDDEDATA hdd, DWORD dwData1, DWORD dwData2);
  112.     void EnterCrit(void) { ASSERT(_fCSInitialized); EnterCriticalSection(&_csIEDDE); }
  113.     void LeaveCrit(void) { ASSERT(_fCSInitialized); LeaveCriticalSection(&_csIEDDE); }
  114. protected:
  115.     BOOL _fAutomationReady;
  116.     HDSA _hdsaWinitem;
  117.     HDSA _hdsaProtocolHandler;
  118.     HDPA _hdpaUrlEcho;
  119.     BOOL _fCSInitialized;
  120.     CRITICAL_SECTION _csIEDDE;
  121.     HDDEDATA _SendDDEMessageHsz(DWORD dwDDEInst, HSZ hszApp, HSZ hszTopic, HSZ hszMessage, UINT wType);
  122.     HDDEDATA _SendDDEMessageSz(DWORD dwDDEInst, LPCTSTR pszApp, LPCTSTR pszTopic, LPCTSTR pszMessage, UINT wType);
  123.     static int _DestroyProtocol(LPVOID p1, LPVOID p2);
  124.     static int _DestroyUrlEcho(LPVOID p1, LPVOID p2);
  125.     static int _DestroyWinitem(LPVOID p1, LPVOID p2);
  126.     BOOL _GetWinitemFromThread(DWORD dwThreadID, WINITEM *pwi);
  127.     BOOL _GetDtiFromThread(DWORD dwThreadID, DDETHREADINFO *pdti);
  128.     BOOL _CreateDdeThreadInfo(DDETHREADINFO *pdti);
  129.     void _DestroyDdeThreadInfo(DDETHREADINFO *pdti);
  130.     BOOL _AddWinitem(WINITEM *pwi);
  131.     BOOL _UpdateWinitem(WINITEM *pwi);
  132.     BOOL _DeleteWinitemByHwnd(HWND hwnd, WINITEM *pwi);
  133.     BOOL _Initialize(void);
  134.     void _Uninitialize(void);
  135.     void _AutomationStarted(void);
  136.     HRESULT _BeforeNavigate(LPCTSTR pszURL, BOOL *pfProcessed);
  137.     HRESULT _AfterNavigate(LPCTSTR pszURL, HWND hwnd);
  138.     BOOL _NewWindow(HWND hwnd);
  139.     BOOL _WindowDestroyed(HWND hwnd);
  140.     friend BOOL IEDDE_Initialize(void);
  141.     friend void IEDDE_Uninitialize(void);
  142.     friend void IEDDE_AutomationStarted(void);
  143.     friend HRESULT IEDDE_BeforeNavigate(LPCWSTR pwszURL, BOOL *pfProcessed);
  144.     friend HRESULT IEDDE_AfterNavigate(LPCWSTR pwszURL, HWND hwnd);
  145.     friend BOOL IEDDE_NewWindow(HWND hwnd);
  146.     friend BOOL IEDDE_WindowDestroyed(HWND hwnd);
  147. };
  148. CIEDDE *g_pIEDDE = NULL;
  149. #define ENTER_IEDDE_CRIT g_pIEDDE->EnterCrit()
  150. #define LEAVE_IEDDE_CRIT g_pIEDDE->LeaveCrit()
  151. //
  152. // There is one CIEDDEThread object per browser window.
  153. // Its private data consists of DDE handles, which are
  154. // necessarily valid only in the thread that created them.
  155. //
  156. // Its methods consist of three broad categories:
  157. //      the parser
  158. //      the dispatcher
  159. //      one handler for each DDE topic
  160. //
  161. //
  162. // CreateReturnObject - creates a dde data item.
  163. //
  164. #define CREATE_HDD(x) CreateReturnObject(&x, SIZEOF(x))
  165. HDDEDATA CIEDDEThread::CreateReturnObject(LPVOID p, DWORD cb)
  166. {
  167.     HDDEDATA hddRet;
  168.     ENTERPROC(2, TEXT("CreateReturnObject(p=%08X,cb=%d)"), p, cb);
  169.     hddRet = DdeCreateDataHandle(_dti.dwDDEInst, (BYTE *)p, cb, 0, _dti.hszReturn, CF_TEXT, 0);
  170.     if (hddRet == 0)
  171.     {
  172.         TraceMsg(TF_WARNING, "IEDDE: Could not create return object");
  173.     }
  174.     EXITPROC(2, TEXT("CreateReturnObject=%08X"), hddRet);
  175.     return hddRet;
  176. }
  177. HDDEDATA CIEDDEThread::CreateReturnStringObject(LPTSTR pszReturnString, DWORD cch)
  178. {
  179.     HDDEDATA hddRet = 0;
  180.     ENTERPROC(2, TEXT("CreateReturnStringObject(p=%s,cb=%d)"), pszReturnString, cch);
  181.     //
  182.     // REVIEW I thought specifying CF_UNICODETEXT should have worked, but... 
  183.     // it didn't, so always return ANSI string as out string params
  184.     // - julianj
  185.     //
  186.     LPSTR pszAnsiBuf = (LPSTR)LocalAlloc(LPTR, cch+1);
  187.     if (pszAnsiBuf)
  188.     {
  189.         SHUnicodeToAnsi(pszReturnString, pszAnsiBuf, cch+1);
  190.         hddRet = DdeCreateDataHandle(_dti.dwDDEInst, (BYTE *)pszAnsiBuf, (cch+1), 0, _dti.hszReturn, CF_TEXT, 0);
  191.         LocalFree(pszAnsiBuf);
  192.     }
  193.     
  194.     if (hddRet == 0)
  195.     {
  196.         TraceMsg(TF_WARNING, "IEDDE: Could not create return object");
  197.     }
  198.     EXITPROC(2, TEXT("CreateReturnObject=%08X"), hddRet);
  199.     return hddRet;
  200. }
  201. //
  202. // OnRequestPoke - handle XTYP_REQUEST and XTYP_POKE
  203. //
  204. HDDEDATA CIEDDEThread::OnRequestPoke(HSZ hszTopic, HSZ hszParams)
  205. {
  206.     HDDEDATA hddRet = 0;
  207.     ENTERPROC(2, TEXT("OnRequestPoke(hszTopic=%08X,hszParams=%08X)"), hszTopic, hszParams);
  208.     TCHAR szTopic[100];
  209.     TCHAR szParams[1000];
  210.     if (DdeQueryString(_dti.dwDDEInst, hszTopic, szTopic, ARRAYSIZE(szTopic), CP_WINNEUTRAL) != 0)
  211.     {
  212.         if (DdeQueryString(_dti.dwDDEInst, hszParams, szParams, ARRAYSIZE(szParams), CP_WINNEUTRAL))
  213.         {
  214.             hddRet = CallTopic(XTYP_REQUEST, szTopic, szParams);
  215.         }
  216.         else
  217.         {
  218.             TraceMsg(TF_WARNING, "IEDDE: OnRequestPoke could not query the parameters");
  219.         }
  220.     }
  221.     else
  222.     {
  223.         TraceMsg(TF_WARNING, "IEDDE: OnRequestPoke could not query the topic");
  224.     }
  225.     EXITPROC(2, TEXT("OnRequestPoke=%08X"), hddRet);
  226.     return hddRet;
  227. }
  228. //
  229. // OnExecute - handle XTYP_EXECUTE
  230. //
  231. HDDEDATA CIEDDEThread::OnExecute(HSZ hszTopic, HDDEDATA hddParams)
  232. {
  233.     HDDEDATA hddRet = 0;
  234.     ENTERPROC(2, TEXT("OnExecute(hszTopic=%08X,hddParams=%08X)"), hszTopic, hddParams);
  235.     TCHAR szTopic[100];
  236.     if (DdeQueryString(_dti.dwDDEInst, hszTopic, szTopic, ARRAYSIZE(szTopic), CP_WINNEUTRAL) != 0)
  237.     {
  238.         //
  239.         // Why "cbParams + 3"?
  240.         // UNICODE - if we cut the last unicode character in half, we need
  241.         //           one 0 to finish the character, and two more 0 for the
  242.         //           terminating NULL
  243.         // ANSI - if we cut the last DBCS character in half, we need one 0
  244.         //        to finish the character, and one 0 for the terminating NULL
  245.         //
  246.         //
  247.         DWORD cbParams = DdeGetData(hddParams, NULL, 0, 0) + 3;
  248.         LPTSTR pszParams = (LPTSTR) LocalAlloc(LPTR, cbParams);
  249.         if(pszParams)
  250.         {
  251.             DdeGetData(hddParams, (BYTE *)pszParams, cbParams, 0);
  252.             //
  253.             // DdeGetData can't be wrapped in shlwapi since it can return non
  254.             // string data.  Here we only expect strings so the result can be
  255.             // safely converted.
  256.             //
  257.             if (g_fRunningOnNT)
  258.             {
  259.                 hddRet = CallTopic(XTYP_EXECUTE, szTopic, pszParams);
  260.             }
  261.             else
  262.             {
  263.                 WCHAR szParams[MAX_URL_STRING];
  264.                 SHAnsiToUnicode((LPCSTR)pszParams, szParams, ARRAYSIZE(szParams));
  265.                 hddRet = CallTopic(XTYP_EXECUTE, szTopic, szParams);
  266.             }
  267.             LocalFree(pszParams);
  268.         }
  269.         else
  270.         {
  271.             TraceMsg(TF_WARNING, "IEDDE: OnExecute could not query the topic");
  272.         }
  273.     }
  274.     else
  275.     {
  276.         TraceMsg(TF_WARNING, "IEDDE: OnExecute could not query the topic");
  277.     }
  278.     EXITPROC(2, TEXT("OnExecute=%08X"), hddRet);
  279.     return hddRet;
  280. }
  281. //
  282. // CallTopic - Looks up the command in the DDETOPICHANDLER table and calls the
  283. // corresponding function.
  284. //
  285. HDDEDATA CIEDDEThread::CallTopic(DWORD dwType, LPCTSTR pszTopic, LPTSTR pszParams)
  286. {
  287.     HDDEDATA hddRet = DDE_FNOTPROCESSED;
  288.     ENTERPROC(2, TEXT("CallTopic(wType=%d,pszTopic=>%s<,pszParams=>%s<)"), dwType, pszTopic, pszParams);
  289. #define DISPATCH_BEGIN
  290. #define DISPATCH(topic)                                 
  291.     if (StrCmpI(TEXT("WWW_") TEXT(#topic), pszTopic) == 0)   
  292.     {                                                   
  293.         if (fCanRun)                                    
  294.         {                                               
  295.             hddRet = WWW_ ## topic(pszParams);          
  296.         }                                               
  297.         else                                            
  298.         {                                               
  299.             fAbortedRun = TRUE;                         
  300.         }                                               
  301.     }                                                   
  302.     else
  303. #define DISPATCH_END { TraceMsg(TF_WARNING, "IEDDE: CallTopic given unknown topic"); }
  304.     BOOL fAbortedRun = FALSE;
  305.     BOOL fCanRun = ((dwType != XTYP_EXECUTE) || g_pIEDDE->IsAutomationReady());
  306.     DISPATCH_BEGIN
  307.         DISPATCH(GetWindowInfo)
  308.         DISPATCH(OpenURL)
  309.         DISPATCH(ShowFile)
  310.         DISPATCH(Activate)
  311.         DISPATCH(Exit)
  312.         DISPATCH(RegisterURLEcho)
  313.         DISPATCH(UnregisterURLEcho)
  314.         DISPATCH(RegisterProtocol)
  315.         DISPATCH(UnregisterProtocol)
  316.         DISPATCH(ListWindows)
  317.     DISPATCH_END
  318.     if (fAbortedRun)
  319.     {
  320.         hddRet = (HDDEDATA)DDE_FACK;
  321.         TraceMsg(TF_WARNING, "IEDDE: CallTopic received XTYP_EXECUTE before Automation was ready - not processing");
  322.     }
  323.     EXITPROC(2, TEXT("CallTopic=%08X"), hddRet);
  324.     return hddRet;
  325. }
  326. //
  327. // ParseString - parse one string
  328. //
  329. BOOL CIEDDEThread::ParseString(LPTSTR *ppsz, LPTSTR *ppszString)
  330. {
  331.     BOOL fRet = FALSE;
  332.     ENTERPROC(3, TEXT("ParseString(ppsz=%08X,ppszString=%08X)"), ppsz, ppszString);
  333.     LPTSTR pchCurrent, pchNext;
  334.     BOOL fInQuote = FALSE;
  335.     pchCurrent = pchNext = *ppsz;
  336.     while (*pchNext)
  337.     {
  338.         switch (*pchNext)
  339.         {
  340.         case TEXT(' '):
  341.         case TEXT('t'):
  342.             if (fInQuote)
  343.             {
  344.                 //
  345.                 // Skip over whitespace when not inside quotes.
  346.                 //
  347.                 *pchCurrent++ = *pchNext;
  348.             }
  349.             pchNext++;
  350.             break;
  351.         case TEXT('"'):
  352.             //
  353.             // Always copy quote marks.
  354.             //
  355.             fInQuote = !fInQuote;
  356.             *pchCurrent++ = *pchNext++;
  357.             break;
  358.         case TEXT(','):
  359.             if (!fInQuote)
  360.             {
  361.                 goto done_parsing;
  362.             }
  363.             *pchCurrent++ = *pchNext++;
  364.             break;
  365.         case TEXT('\'):
  366.             if (fInQuote &&
  367.                 (*(pchNext+1) == TEXT('"')))
  368.             {
  369.                 //
  370.                 // When in quotes, a " becomes a ".
  371.                 //
  372.                 pchNext++;
  373.             }
  374.             *pchCurrent++ = *pchNext++;
  375.             break;
  376.         default:
  377.             *pchCurrent++ = *pchNext++;
  378.             break;
  379.         }
  380.     }
  381. done_parsing:
  382.     //
  383.     // Advance past the comma separator.
  384.     //
  385.     if (*pchNext == TEXT(','))
  386.     {
  387.         pchNext++;
  388.     }
  389.     //
  390.     // NULL terminate the return string.
  391.     //
  392.     *pchCurrent = TEXT('');
  393.     //
  394.     // Set the return values.
  395.     //
  396.     *ppszString = *ppsz;
  397.     *ppsz = pchNext;
  398.     fRet = TRUE;
  399.     EXITPROC(3, TEXT("ParseString=%d"), fRet);
  400.     return fRet;
  401. }
  402. //
  403. // ParseQString - parse one quoted string
  404. //
  405. BOOL CIEDDEThread::ParseQString(LPTSTR *ppsz, LPTSTR *ppszString)
  406. {
  407.     BOOL fRet = FALSE;
  408.     ENTERPROC(3, TEXT("ParseQString(ppsz=%08X,ppszString=%08X)"), ppsz, ppszString);
  409.     if (ParseString(ppsz, ppszString))
  410.     {
  411.         LPTSTR pszString = *ppszString;
  412.         int cch = lstrlen(pszString);
  413.         //
  414.         // Strip off optional outer quotes.
  415.         //
  416.         if ((cch >= 2) &&
  417.             (pszString[0] == TEXT('"')) &&
  418.             (pszString[cch-1] == TEXT('"')))
  419.         {
  420.             pszString[0] = pszString[cch-1] = TEXT('');
  421.             *ppszString = pszString + 1;
  422.         }
  423.         fRet = TRUE;
  424.     }
  425.     EXITPROC(3, TEXT("ParseQString=%d"), fRet);
  426.     return fRet;
  427. }
  428. //
  429. // ParseNumber - parse one numeric value
  430. //
  431. BOOL CIEDDEThread::ParseNumber(LPTSTR *ppsz, DWORD *pdw)
  432. {
  433.     BOOL fRet = FALSE;
  434.     LPTSTR pszNumber;
  435.     ENTERPROC(3, TEXT("GetNumber(ppsz=%08X,pdw=%08X)"), ppsz, pdw);
  436.     if (ParseString(ppsz, &pszNumber) && pszNumber[0])
  437.     {
  438.         StrToIntEx(pszNumber, STIF_SUPPORT_HEX, (int *)pdw);
  439.         fRet = TRUE;
  440.     }
  441.     EXITPROC(3, TEXT("GetNumber=%d"), fRet);
  442.     return fRet;
  443. }
  444. //
  445. // ParseWinitem - parse one window ID, and return the winitem
  446. //
  447. BOOL CIEDDEThread::ParseWinitem(LPTSTR *ppsz, WINITEM *pwi)
  448. {
  449.     BOOL fRet = FALSE;
  450.     DWORD dwWindowID;
  451.     ENTERPROC(3, TEXT("ParseWinitem(ppsz=%08X,pwi=%08X)"), ppsz, pwi);
  452.     if (ParseNumber(ppsz, &dwWindowID))
  453.     {
  454.         switch (dwWindowID)
  455.         {
  456.         case 0:
  457.         case -1:
  458.             ZeroMemory(pwi, SIZEOF(*pwi));
  459.             pwi->dwWindowID = dwWindowID;
  460.             pwi->hwnd = (HWND)LongToHandle(dwWindowID);
  461.             fRet = TRUE;
  462.             break;
  463.         default:
  464.             fRet = g_pIEDDE->GetWinitemFromWindowID(dwWindowID, pwi);
  465.             break;
  466.         }
  467.     }
  468.     EXITPROC(3, TEXT("ParseWinitem=%d"), fRet);
  469.     return fRet;
  470. }
  471. //
  472. //  WWW_GetWindowInfo - get information about a browser window
  473. //
  474. //  Parameters:
  475. //      dwWindowID - Window ID to examine (-1 = last active window)
  476. //
  477. //  Returns:
  478. //      qcsURL,qcsTitle
  479. //
  480. HDDEDATA CIEDDEThread::WWW_GetWindowInfo(LPTSTR pszParams)
  481. {
  482.     HDDEDATA hddRet = 0;
  483.     WINITEM wi;
  484.     ENTERPROC(1, TEXT("WWW_GetWindowInfo(pszParams=>%s<)"), pszParams);
  485.     if (ParseWinitem(&pszParams, &wi) &&
  486.         (wi.hwnd != 0))
  487.     {
  488.         BSTR bstrURL;
  489.         if (SUCCEEDED(CDDEAuto_get_LocationURL(&bstrURL, wi.hwnd)) && (bstrURL != (BSTR)-1))
  490.         {
  491.             BSTR bstrTitle;
  492.             if (SUCCEEDED(CDDEAuto_get_LocationTitle(&bstrTitle, wi.hwnd)) && (bstrTitle != (BSTR)-1))
  493.             {
  494.                 LPTSTR pszURL, pszTitle;
  495.                 pszURL = bstrURL;
  496.                 pszTitle = bstrTitle;
  497.                 if (pszURL && pszTitle)
  498.                 {
  499.                     TCHAR szURLQ[MAX_URL_STRING];
  500.                     TCHAR szTitleQ[MAX_URL_STRING];
  501.                     if (MakeQuotedString(pszURL, szURLQ, ARRAYSIZE(szURLQ)) &&
  502.                         MakeQuotedString(pszTitle, szTitleQ, ARRAYSIZE(szTitleQ)))
  503.                     {
  504.                         DWORD cchBuffer = lstrlen(szURLQ) + 1 + lstrlen(szTitleQ) + 1;
  505.                         LPTSTR pszBuffer = (LPTSTR)LocalAlloc(LPTR, cchBuffer * SIZEOF(TCHAR));
  506.                         if (pszBuffer)
  507.                         {
  508.                             wnsprintf(pszBuffer, cchBuffer, TEXT("%s,%s"), szURLQ, szTitleQ);
  509.                             hddRet = CreateReturnStringObject(pszBuffer, lstrlen(pszBuffer));
  510.                             LocalFree(pszBuffer);
  511.                         }
  512.                         else
  513.                         {
  514.                             TraceMsg(TF_WARNING, "IEDDE: GetWindowInfo could not alloc buffer");
  515.                         }
  516.                     }
  517.                     else
  518.                     {
  519.                         TraceMsg(TF_WARNING, "IEDDE: GetWindowInfo could not quote return strings");
  520.                     }
  521.                 }
  522.                 SysFreeString(bstrTitle);
  523.             }
  524.             else
  525.             {
  526.                 TraceMsg(TF_WARNING, "IEDDE: GetWindowInfo could not get title");
  527.             }
  528.             SysFreeString(bstrURL);
  529.         }
  530.         else
  531.         {
  532.             TraceMsg(TF_WARNING, "IEDDE: GetWindowInfo could not get URL");
  533.         }
  534.     }
  535.     else
  536.     {
  537.         TraceMsg(TF_WARNING, "IEDDE: GetWindowInfo could not parse parameters");
  538.     }
  539.     EXITPROC(1, TEXT("WWW_GetWindowInfo=%08X"), hddRet);
  540.     return hddRet;
  541. }
  542. //
  543. //  WWW_OpenURL - navigate to a URL
  544. //
  545. //  Parameters:
  546. //      qcsURL - url to navigate to
  547. //      qcsSaveFile - [optional] file to save contents in
  548. //      dwWindowID - Window ID to perform navigation
  549. //      dwFlags - flags for navigation
  550. //      qcsPostFormData - [optional] form data to post to URL
  551. //      qcsPostMIMEType - [optional] mime type for form data
  552. //      csProgressServer - [optional] DDE server to get progress updates
  553. //
  554. //  Returns:
  555. //      dwWindowID - window which is doing the work
  556. //
  557. HDDEDATA CIEDDEThread::WWW_OpenURL(LPTSTR pszParams)
  558. {
  559.     HDDEDATA hddRet = 0;
  560.     LPTSTR pszUrl, pszFile;
  561.     WINITEM wi;
  562.     ENTERPROC(1, TEXT("WWW_OpenURL(pszParams=>%s<)"), pszParams);
  563.     if (*pszParams == TEXT(''))
  564.     {
  565.         // An empty string is a NOOP.  Needed for NT #291766
  566.     }
  567.     else if (ParseQString(&pszParams, &pszUrl) &&
  568.              ParseQString(&pszParams, &pszFile))
  569.     {
  570.         //
  571.         // APPCOMPAT - a missing hwnd parameter implies -1.
  572.         //
  573.         if (!ParseWinitem(&pszParams, &wi))
  574.         {
  575.             TraceMsg(TF_WARNING, "IEDDE: Some bozo isn't giving the required hwnd parameter to WWW_OpenURL, assuming -1");
  576.             wi.hwnd = (HWND)-1;
  577.         }
  578. #ifdef DEBUG
  579.         DWORD dwFlags;
  580.         if (!ParseNumber(&pszParams, &dwFlags))
  581.         {
  582.             TraceMsg(TF_WARNING, "IEDDE: Some bozo isn't giving the required dwFlags parameter to WWW_OpenURL");
  583.         }
  584. #endif
  585.         hddRet = DoNavigate(pszUrl, wi.hwnd);
  586.     }
  587.     else
  588.     {
  589.         TraceMsg(TF_WARNING, "IEDDE: OpenURL could not parse parameters");
  590.     }
  591.     EXITPROC(1, TEXT("WWW_OpenURL=%08X"), hddRet);
  592.     return hddRet;
  593. }
  594. //
  595. //  WWW_ShowFile - navigate to a file
  596. //
  597. //  Parameters:
  598. //      qcsFilename - file to load
  599. //      qcsPostMIMEType - [optional] mime type for form data
  600. //      dwWindowID - Window ID to perform navigation
  601. //      qcsURL - URL of the same document
  602. //
  603. //  Returns:
  604. //      dwWindowID - window which is doing the work
  605. //
  606. HDDEDATA CIEDDEThread::WWW_ShowFile(LPTSTR pszParams)
  607. {
  608.     HDDEDATA hddRet = 0;
  609.     LPTSTR pszFilename, pszMIMEType;
  610.     WINITEM wi;
  611.     ENTERPROC(1, TEXT("WWW_ShowFile(pszParams=>%s<)"), pszParams);
  612.     if (ParseQString(&pszParams, &pszFilename) && pszFilename[0])
  613.     {
  614.         if (!ParseQString(&pszParams, &pszMIMEType) || !pszMIMEType[0])
  615.         {
  616.             TraceMsg(TF_WARNING, "IEDDE: Some bozo isn't giving the required MIMEType parameter to WWW_ShowFile");
  617.         }
  618.         if (!ParseWinitem(&pszParams, &wi))
  619.         {
  620.             TraceMsg(TF_WARNING, "IEDDE: Some bozo isn't giving the required dwWindowID parameter to WWW_ShowFile, assuming -1");
  621.             wi.hwnd = (HWND)-1;
  622.         }
  623. #ifdef DEBUG
  624.         LPTSTR pszURL;
  625.         if (!ParseQString(&pszParams, &pszURL) || !pszURL[0])
  626.         {
  627.             TraceMsg(TF_WARNING, "IEDDE: Some bozo isn't giving the required szURL parameter to WWW_ShowFile");
  628.         }
  629. #endif
  630.         hddRet = DoNavigate(pszFilename, wi.hwnd);
  631.     }
  632.     else
  633.     {
  634.         TraceMsg(TF_WARNING, "IEDDE: ShowFile could not parse parameters");
  635.     }
  636.     EXITPROC(1, TEXT("WWW_ShowFile=%08X"), hddRet);
  637.     return hddRet;
  638. }
  639. //
  640. // DoNavigate - navigate to a location
  641. //
  642. HDDEDATA CIEDDEThread::DoNavigate(LPTSTR pszLocation, HWND hwnd)
  643. {
  644.     HDDEDATA hddRet = 0;
  645.     HRESULT hr = S_OK;
  646.     TCHAR szParsedPath[MAX_URL_STRING+1];
  647.     DWORD cchParsedPath = ARRAYSIZE(szParsedPath);
  648.     ENTERPROC(2, TEXT("DoNavigate(pszLocation=>%s<,hwnd=%08X)"), pszLocation, hwnd);
  649.     //
  650.     // Convert URL from outside format to internal format.
  651.     //
  652.     if (ParseURLFromOutsideSource(pszLocation, szParsedPath, &cchParsedPath, NULL))
  653.     {
  654.         pszLocation = szParsedPath;
  655.     }
  656.     //
  657.     // In the case of a file:// URL, convert the location to a path.
  658.     //
  659.     cchParsedPath = ARRAYSIZE(szParsedPath);
  660.     if (IsFileUrlW(pszLocation) && SUCCEEDED(PathCreateFromUrl(pszLocation, szParsedPath, &cchParsedPath, 0)))
  661.     {
  662.         pszLocation = szParsedPath;
  663.     }
  664.     LPWSTR pwszPath;
  665.     pwszPath = pszLocation;
  666.     if (SUCCEEDED(hr))
  667.     {
  668.         hr = CDDEAuto_Navigate(pwszPath, &hwnd, 0);
  669.     }
  670.     DWORD dwServicingWindow = SUCCEEDED(hr) ? -2 : -3;
  671.     hddRet = CREATE_HDD(dwServicingWindow);
  672.     EXITPROC(2, TEXT("DoNavigate=%08X"), hddRet);
  673.     return hddRet;
  674. }
  675. //
  676. //  WWW_Activate - activate a browser window
  677. //
  678. //  Parameters:
  679. //      dwWindowID - Window ID to activate
  680. //      dwFlags - should always zero
  681. //
  682. //  Returns:
  683. //      dwWindowID - window ID that got activated
  684. //
  685. HDDEDATA CIEDDEThread::WWW_Activate(LPTSTR pszParams)
  686. {
  687.     HDDEDATA hddRet = 0;
  688.     WINITEM wi;
  689.     ENTERPROC(1, TEXT("WWW_Activate(pszParams=>%s<)"), pszParams);
  690.     if (ParseWinitem(&pszParams, &wi) &&
  691.         wi.dwWindowID != 0)
  692.     {
  693. #ifdef DEBUG
  694.         DWORD dwFlags;
  695.         if (ParseNumber(&pszParams, &dwFlags))
  696.         {
  697.             //
  698.             // Netscape spec says this should always be zero.
  699.             //
  700.             ASSERT(dwFlags == 0);
  701.         }
  702.         else
  703.         {
  704.             TraceMsg(TF_WARNING, "IEDDE: Some bozo isn't giving the required dwFlags parameter to WWW_Activate");
  705.         }
  706. #endif
  707.         //
  708.         // dwWindowID of -1 means use the active window.
  709.         //
  710.         if (wi.dwWindowID == -1)
  711.         {
  712.             HWND hwnd;
  713.             CDDEAuto_get_HWND((long *)&hwnd);
  714.             if (hwnd)
  715.             {
  716.                 if (g_pIEDDE->GetWinitemFromHwnd(hwnd, &wi) == FALSE)
  717.                 {
  718.                     wi.dwWindowID = (DWORD)-1;
  719.                 }
  720.             }
  721.             else
  722.             {
  723.                 TraceMsg(TF_WARNING, "IEDDE: Activate could not find an active window");
  724.             }
  725.         }
  726.         //
  727.         // Activate the window.
  728.         //
  729.         if (wi.dwWindowID != -1)
  730.         {
  731.             if ((GetForegroundWindow() == wi.hwnd) || (SetForegroundWindow(wi.hwnd)))
  732.             {
  733.                 if (IsIconic(wi.hwnd))
  734.                 {
  735.                     ShowWindow(wi.hwnd, SW_RESTORE);
  736.                 }
  737.             }
  738.             else
  739.             {
  740.                 TraceMsg(TF_WARNING, "IEDDE: Activate could not set foreground window");
  741.             }
  742.             
  743.             hddRet = CREATE_HDD(wi.dwWindowID);
  744.         }
  745.         else
  746.         {
  747.             TraceMsg(TF_WARNING, "IEDDE: Activate could not find a browser window to activate");
  748.         }
  749.     }
  750.     else
  751.     {
  752.         TraceMsg(TF_WARNING, "IEDDE: Activate could not parse parameters");
  753.     }
  754.     EXITPROC(1, TEXT("WWW_Activate=%08X"), hddRet);
  755.     return hddRet;
  756. }
  757. //
  758. //  WWW_Exit - close all browser windows
  759. //
  760. //  Parameters:
  761. //      none
  762. //
  763. //  Returns:
  764. //      none
  765. //
  766. HDDEDATA CIEDDEThread::WWW_Exit(LPTSTR pszParams)
  767. {
  768.     HDDEDATA hddRet = 0;
  769.     ENTERPROC(1, TEXT("WWW_Exit(pszParams=>%s<)"), pszParams);
  770.     CDDEAuto_Exit();
  771.     EXITPROC(1, TEXT("WWW_Exit=%08X"), hddRet);
  772.     return hddRet;
  773. }
  774. //
  775. //  WWW_RegisterURLEcho - register a server for URL change notifications
  776. //
  777. //  Parameters:
  778. //      qcsServer - the DDE server to get notifications
  779. //
  780. //  Returns:
  781. //      fSuccess
  782. //
  783. HDDEDATA CIEDDEThread::WWW_RegisterURLEcho(LPTSTR pszParams)
  784. {
  785.     HDDEDATA hddRet = 0;
  786.     BOOL fSuccess = FALSE;
  787.     LPTSTR pszServer;
  788.     ENTERPROC(1, TEXT("WWW_RegisterURLEcho(pszParams=>%s<)"), pszParams);
  789.     if (ParseQString(&pszParams, &pszServer) && pszServer[0])
  790.     {
  791.         LPTSTR pszServerCopy = StrDup(pszServer);
  792.         if (pszServerCopy)
  793.         {
  794.             if (g_pIEDDE->AddUrlEcho(pszServerCopy))
  795.             {
  796.                 fSuccess = TRUE;
  797.             }
  798.             else
  799.             {
  800.                 TraceMsg(TF_WARNING, "IEDDE: RegisterURLEcho could not add an URLEcho");
  801.             }
  802.             if (!fSuccess)
  803.             {
  804.                 LocalFree(pszServerCopy);
  805.             }
  806.         }
  807.         else
  808.         {
  809.             TraceMsg(TF_WARNING, "IEDDE: RegisterURLEcho could not dup a string");
  810.         }
  811.     }
  812.     else
  813.     {
  814.         TraceMsg(TF_WARNING, "IEDDE: RegisterURLEcho could not parse parameters");
  815.     }
  816.     hddRet = CREATE_HDD(fSuccess);
  817.     EXITPROC(1, TEXT("WWW_RegisterURLEcho=%08X"), hddRet);
  818.     return hddRet;
  819. }
  820. //
  821. //  WWW_UnregisterURLEcho - unregister a DDE server
  822. //
  823. //  Parameters:
  824. //      qcsServer - the DDE server to stop getting notifications
  825. //
  826. //  Returns:
  827. //      fSuccess
  828. //
  829. HDDEDATA CIEDDEThread::WWW_UnregisterURLEcho(LPTSTR pszParams)
  830. {
  831.     HDDEDATA hddRet = 0;
  832.     BOOL fSuccess = FALSE;
  833.     LPTSTR pszServer;
  834.     ENTERPROC(1, TEXT("WWW_UnregisterURLEcho(pszParams=>%s<)"), pszParams);
  835.     if (ParseQString(&pszParams, &pszServer) && pszServer[0])
  836.     {
  837.         if (g_pIEDDE->RemoveUrlEcho(pszServer))
  838.         {
  839.             fSuccess = TRUE;
  840.         }
  841.         else
  842.         {
  843.             TraceMsg(TF_WARNING, "IEDDE: UnregisterURLEcho could not find the server");
  844.         }
  845.     }
  846.     else
  847.     {
  848.         TraceMsg(TF_WARNING, "IEDDE: UnregisterURLEcho could not parse parameters");
  849.     }
  850.     hddRet = CREATE_HDD(fSuccess);
  851.     EXITPROC(1, TEXT("WWW_UnregisterURLEcho=%08X"), hddRet);
  852.     return hddRet;
  853. }
  854. //
  855. //  WWW_RegisterProtocol - register a server for handling a protocol
  856. //
  857. //  Parameters:
  858. //      qcsServer - the DDE server to handle URLs
  859. //      qcsProtocol - the protocol to handle
  860. //
  861. //  Returns:
  862. //      fSuccess - this is the first server to register the protocol
  863. //
  864. HDDEDATA CIEDDEThread::WWW_RegisterProtocol(LPTSTR pszParams)
  865. {
  866.     HDDEDATA hddRet = 0;
  867.     BOOL fSuccess = FALSE;
  868.     LPTSTR pszServer, pszProtocol;
  869.     ENTERPROC(1, TEXT("WWW_RegisterProtocol(pszParams=>%s<)"), pszParams);
  870.     if (ParseQString(&pszParams, &pszServer) && pszServer[0] &&
  871.         ParseQString(&pszParams, &pszProtocol) && pszProtocol[0])
  872.     {
  873.         if (g_pIEDDE->AddProtocolHandler(pszServer, pszProtocol))
  874.         {
  875.             fSuccess = TRUE;
  876.         }
  877.         else
  878.         {
  879.             TraceMsg(TF_WARNING, "IEDDE: RegisterProtocol unable to register");
  880.         }
  881.     }
  882.     else
  883.     {
  884.         TraceMsg(TF_WARNING, "IEDDE: RegisterProtocol could not parse parameters");
  885.     }
  886.     hddRet = CREATE_HDD(fSuccess);
  887.     EXITPROC(1, TEXT("WWW_RegisterProtocol=%08X"), hddRet);
  888.     return hddRet;
  889. }
  890. //
  891. //  WWW_UnregisterProtocol - unregister a server handling a protocol
  892. //
  893. //  Parameters:
  894. //      qcsServer - the DDE server which is handling URLs
  895. //      qcsProtocol - the protocol getting handled
  896. //
  897. //  Returns:
  898. //      fSuccess - this server was registered, but now isn't
  899. //
  900. HDDEDATA CIEDDEThread::WWW_UnregisterProtocol(LPTSTR pszParams)
  901. {
  902.     HDDEDATA hddRet = 0;
  903.     BOOL fSuccess = FALSE;
  904.     LPTSTR pszServer, pszProtocol;
  905.     ENTERPROC(1, TEXT("WWW_UnregisterProtocol(pszParams=>%s<)"), pszParams);
  906.     if (ParseQString(&pszParams, &pszServer) && pszServer[0] &&
  907.         ParseQString(&pszParams, &pszProtocol) && pszProtocol[0])
  908.     {
  909.         if (g_pIEDDE->RemoveProtocolHandler(pszServer, pszProtocol))
  910.         {
  911.             fSuccess = TRUE;
  912.         }
  913.         else
  914.         {
  915.             TraceMsg(TF_WARNING, "IEDDE: UnregisterProtocol unable to unregister");
  916.         }
  917.     }
  918.     else
  919.     {
  920.         TraceMsg(TF_WARNING, "IEDDE: UnregisterProtocol could not parse parameters");
  921.     }
  922.     hddRet = CREATE_HDD(fSuccess);
  923.     EXITPROC(1, TEXT("WWW_UnregisterProtocol=%08X"), hddRet);
  924.     return hddRet;
  925. }
  926. //
  927. //  WWW_ListWindows - Get a list of DDE supported browser window IDs
  928. //
  929. //  Parameters:
  930. //      none
  931. //
  932. //  Returns:
  933. //      pdwWindowID (terminated with 0)
  934. //
  935. HDDEDATA CIEDDEThread::WWW_ListWindows(LPTSTR pszParams)
  936. {
  937.     HDDEDATA hddRet = 0;
  938.     ENTERPROC(1, TEXT("WWW_ListWindows(pszParams=>%s<)"), pszParams);
  939.     ENTER_IEDDE_CRIT;
  940.     DWORD cbAlloc, *pdwWindowID;
  941.     int cWindows = 0;
  942.     HDSA hdsaWinitem = g_pIEDDE->GetHdsaWinitem();
  943.     if (hdsaWinitem)
  944.     {
  945.         cWindows = DSA_GetItemCount(hdsaWinitem);
  946.     }
  947.     //
  948.     // Note: we are following the Netscape spec (null terminated pdw) here,
  949.     // whereas IE3 followed the Spyglass spec (pdw[0] = count of windows).
  950.     //
  951.     cbAlloc = (cWindows + 1) * SIZEOF(DWORD);
  952.     pdwWindowID = (DWORD *)LocalAlloc(LPTR, cbAlloc);
  953.     if (pdwWindowID)
  954.     {
  955.         DWORD *pdw;
  956.         pdw = pdwWindowID;
  957.         for (int i=0; i<cWindows; i++)
  958.         {
  959.             WINITEM wi;
  960.             int iResult = DSA_GetItem(hdsaWinitem, i, &wi);
  961.             if (iResult != -1)
  962.             {
  963.                 *pdw++ = wi.dwWindowID;
  964.             }
  965.             else
  966.             {
  967.                 TraceMsg(TF_WARNING, "IEDDE: ListWindows could not get a DSA item");
  968.             }
  969.         }
  970.         hddRet = CreateReturnObject(pdwWindowID, cbAlloc);
  971.     }
  972.     else
  973.     {
  974.         TraceMsg(TF_WARNING, "IEDDE: ListWindows could not allocate a window list");
  975.     }
  976.     LEAVE_IEDDE_CRIT;
  977.     EXITPROC(1, TEXT("WWW_ListWindows=%08X"), hddRet);
  978.     return hddRet;
  979. }
  980. //
  981. // MakeQuotedString - wrap a string in " marks, escaping internal "s as "
  982. //
  983. BOOL CIEDDEThread::MakeQuotedString(LPCTSTR pszInput, LPTSTR pszOutput, int cchOutput)
  984. {
  985.     BOOL fRet = FALSE;
  986.     ENTERPROC(2, TEXT("MakeQuotedString(pszInput=>%s<,pszOutput=%08X,cchOutput=%08X)"), pszInput, pszOutput, cchOutput);
  987.     if (cchOutput < 3)
  988.     {
  989.         TraceMsg(TF_WARNING, "IEDDE: MakeQuotedString has no room for minimal quoted string");
  990.     }
  991.     else if ((pszInput == NULL) || (*pszInput == TEXT('')))
  992.     {
  993.         StrCpyN(pszOutput, TEXT(""""), cchOutput);
  994.         fRet = TRUE;
  995.     }
  996.     else
  997.     {
  998.         //
  999.         // Copy first quote mark.
  1000.         //
  1001.         *pszOutput++ = TEXT('"');
  1002.         cchOutput--;
  1003.         //
  1004.         // Copy pszInput, escaping quote marks and making
  1005.         // sure to leave room for final quote and NULL.
  1006.         //
  1007.         while ((cchOutput > 2) && (*pszInput))
  1008.         {
  1009.             if (*pszInput == TEXT('"'))
  1010.             {
  1011.                 *pszOutput++ = TEXT('\');
  1012.                 cchOutput--;
  1013.             }
  1014.             *pszOutput++ = *pszInput++;
  1015.             cchOutput--;
  1016.         }
  1017.         //
  1018.         // Copy final quote and NULL if we're done and there is room.
  1019.         //
  1020.         if ((*pszInput == TEXT('')) && (cchOutput >= 2))
  1021.         {
  1022.             StrCpyN(pszOutput, TEXT("""), cchOutput);
  1023.             fRet = TRUE;
  1024.         }
  1025.         else
  1026.         {
  1027.             TraceMsg(TF_WARNING, "IEDDE: MakeQuotedString ran out of room in output buffer");
  1028.         }
  1029.     }
  1030.     EXITPROC(2, TEXT("MakeQuotedString=%d"), fRet);
  1031.     return fRet;
  1032. }
  1033. #undef CIEDDEThread
  1034. //
  1035. // There is one global CIEDDE object per process.
  1036. // It maintains the global information, such as
  1037. // the list of all browsers & what threads they are on,
  1038. // and the list of all apps who have registered an URL Echo.
  1039. //
  1040. // Its methods consist of these categories:
  1041. //      the DDE callback function
  1042. //      an internal handler for each exposed IEDDE_ function
  1043. //      database (hdsa, hdpa) access and manipulation functions
  1044. //
  1045. // This object creates and destroys CIEDDEThread objects
  1046. // (at NewWindow and WindowDestroyed time) and also initializes /
  1047. // uninitializes DDE services on a per thread (not per hwnd!) basis.
  1048. //
  1049. //
  1050. // DdeCallback - DDE callback function for IEDDE.
  1051. //
  1052. #define DDETYPESTR(x) (x == XTYP_REQUEST ? TEXT("Request") : 
  1053.                        (x == XTYP_POKE ? TEXT("Poke") : 
  1054.                        (x == XTYP_EXECUTE ? TEXT("Execute") : 
  1055.                        (x == XTYP_CONNECT ? TEXT("Connect") : TEXT("Unknown")))))
  1056. HDDEDATA CIEDDE::DdeCallback(UINT dwType, UINT dwFmt, HCONV hconv, HSZ hsz1, HSZ hsz2, HDDEDATA hdd, DWORD dwData1, DWORD dwData2)
  1057. {
  1058.     HDDEDATA    hddRet = 0;
  1059.     ENTERPROC(2, TEXT("DdeCallback(dwType=%08X(%s),dwFmt=%d,hconv=%d,hsz1=%08X,hsz2=%08X,hdd=%08X,dwData1=%08X,dwData2=%08X)"),
  1060.                 dwType, DDETYPESTR(dwType), dwFmt, hconv, hsz1, hsz2, hdd, dwData1, dwData2);
  1061.     WINITEM wi;
  1062.     switch (dwType)
  1063.     {
  1064.     case XTYP_REQUEST:
  1065.     case XTYP_POKE:
  1066.         if (g_pIEDDE->_GetWinitemFromThread(GetCurrentThreadId(), &wi))
  1067.         {
  1068.             hddRet = wi.pidt->OnRequestPoke(hsz1, hsz2);
  1069.         }
  1070.         else
  1071.         {
  1072.             TraceMsg(TF_WARNING, "IEDDE: DdeCallback unable to get thread info on request / poke");
  1073.         }
  1074.         break;
  1075.     case XTYP_EXECUTE:
  1076.         if (g_pIEDDE->_GetWinitemFromThread(GetCurrentThreadId(), &wi))
  1077.         {
  1078.             hddRet = wi.pidt->OnExecute(hsz1, hdd);
  1079.         }
  1080.         else
  1081.         {
  1082.             TraceMsg(TF_WARNING, "IEDDE: DdeCallback unable to get thread info on execute");
  1083.         }
  1084.         break;
  1085.     case XTYP_CONNECT:
  1086.         if (g_pIEDDE->_GetWinitemFromThread(GetCurrentThreadId(), &wi))
  1087.         {
  1088.             DDETHREADINFO dti;
  1089.             wi.pidt->GetDdeThreadInfo(&dti);
  1090.             hddRet = (HDDEDATA)(hsz2 == dti.hszService);
  1091.         }
  1092.         else
  1093.         {
  1094.             TraceMsg(TF_WARNING, "IEDDE: DdeCallback unable to get thread info on connect");
  1095.         }
  1096.         break;
  1097.     case XTYP_ADVREQ:
  1098.     case XTYP_ADVSTOP:
  1099.         hddRet = DDE_FNOTPROCESSED;
  1100.         break;
  1101.     }
  1102.     EXITPROC(2, TEXT("DdeCallback=%08X"), hddRet);
  1103.     return hddRet;
  1104. }
  1105. //
  1106. // SendDDEMessageHsz - handle based wrapper for doing one DDE client transaction
  1107. //
  1108. HDDEDATA CIEDDE::_SendDDEMessageHsz(DWORD dwDDEInst, HSZ hszApp, HSZ hszTopic, HSZ hszMessage, UINT wType)
  1109. {
  1110.     HDDEDATA hddRet = 0;
  1111.     ENTERPROC(2, TEXT("_SendDDEMessageHsz(dwDDEInst=%08X,hszApp=%08X,hszTopic=%08X,hszMessage=%08X,wType=%d)"), dwDDEInst, hszApp, hszTopic, hszMessage, wType);
  1112.     if (hszApp && hszTopic)
  1113.     {
  1114.         HCONV hconv;
  1115.         
  1116.         hconv = DdeConnect(dwDDEInst, hszApp, hszTopic, NULL);
  1117.         if (hconv)
  1118.         {
  1119.             hddRet = DdeClientTransaction(NULL, 0, hconv, hszMessage, CF_TEXT, wType, TEN_SECONDS, NULL);
  1120.             DdeDisconnect(hconv);
  1121.         }
  1122.         else
  1123.         {
  1124.             TraceMsg(TF_WARNING, "IEDDE: _SendDDEMessageHsz could not connect to app");
  1125.         }
  1126.     }
  1127.     else
  1128.     {
  1129.         TraceMsg(TF_WARNING, "IEDDE: _SendDDEMessageHsz is missing either App or Topic");
  1130.     }
  1131.     EXITPROC(2, TEXT("_SendDDEMessageHsz=%08X"), hddRet);
  1132.     return hddRet;
  1133. }
  1134. //
  1135. // SendDDEMessageSz - string based wrapper for doing one DDE client transaction
  1136. //
  1137. HDDEDATA CIEDDE::_SendDDEMessageSz(DWORD dwDDEInst, LPCTSTR pszApp, LPCTSTR pszTopic, LPCTSTR pszMessage, UINT wType)
  1138. {
  1139.     HDDEDATA hddRet = 0;
  1140.     ENTERPROC(2, TEXT("_SendDDEMessageSz(dwDDEInst=%08X,pszApp=>%s<,pszTopic=>%s<,pszMessage=>%s<,wType=%d)"), dwDDEInst, pszApp, pszTopic, pszMessage, wType);
  1141.     HSZ hszApp = DdeCreateStringHandle(dwDDEInst, pszApp, CP_WINNEUTRAL);
  1142.     if (hszApp)
  1143.     {
  1144.         HSZ hszTopic = DdeCreateStringHandle(dwDDEInst, pszTopic, CP_WINNEUTRAL);
  1145.         if (hszTopic)
  1146.         {
  1147.             HSZ hszMessage = DdeCreateStringHandle(dwDDEInst, pszMessage, CP_WINNEUTRAL);
  1148.             if (hszMessage)
  1149.             {
  1150.                 hddRet = _SendDDEMessageHsz(dwDDEInst, hszApp, hszTopic, hszMessage, wType);
  1151.                 DdeFreeStringHandle(dwDDEInst, hszMessage);
  1152.             }
  1153.             else
  1154.             {
  1155.                 TraceMsg(TF_WARNING, "IEDDE: _SendDDEMessageSz could not convert message");
  1156.             }
  1157.             DdeFreeStringHandle(dwDDEInst, hszTopic);
  1158.         }
  1159.         else
  1160.         {
  1161.             TraceMsg(TF_WARNING, "IEDDE: _SendDDEMessageSz could not convert topic");
  1162.         }
  1163.         DdeFreeStringHandle(dwDDEInst, hszApp);
  1164.     }
  1165.     else
  1166.     {
  1167.         TraceMsg(TF_WARNING, "IEDDE: _SendDDEMessageSz could not convert app");
  1168.     }
  1169.     EXITPROC(2, TEXT("_SendDDEMessageSz=%08X"), hddRet);
  1170.     return hddRet;
  1171. }
  1172. //
  1173. // Initialize - called when ready to start IEDDE server
  1174. //
  1175. BOOL CIEDDE::_Initialize(void)
  1176. {
  1177.     BOOL fSuccess = TRUE;
  1178.     ENTERPROC(2, TEXT("_Initialize()"));
  1179.     ASSERT(_fCSInitialized == FALSE);
  1180.     InitializeCriticalSection(&_csIEDDE);
  1181.     _fCSInitialized = TRUE;
  1182.     EXITPROC(2, TEXT("_Initialize=%d"), fSuccess);
  1183.     return fSuccess;
  1184. }
  1185. //
  1186. // _DestroyWinitem - DSA callback to partially free the contents of a WINITEM*
  1187. //  In practice this should never get called, the hdsaWinItem list should be
  1188. //  empty at uninit time.
  1189. //
  1190. int CIEDDE::_DestroyWinitem(LPVOID p1, LPVOID p2)
  1191. {
  1192.     WINITEM *pwi = (WINITEM *)p1;
  1193.     ASSERT(IS_VALID_READ_PTR(pwi, WINITEM));
  1194.     ASSERT(IS_VALID_READ_PTR(pwi->pidt, CIEDDEThread));
  1195.     //
  1196.     // It would be good to unregister the DDE server at this point,
  1197.     // but we'd need to be on its thread to do it.
  1198.     //
  1199.     delete pwi->pidt;
  1200.     return 1;
  1201. }
  1202. //
  1203. // _DestroyProtocol - DSA callback to free the contents of a PROTOCOLREG*
  1204. //
  1205. int CIEDDE::_DestroyProtocol(LPVOID p1, LPVOID p2)
  1206. {
  1207.     PROTOCOLREG *pr = (PROTOCOLREG *)p1;
  1208.     ASSERT(IS_VALID_READ_PTR(pr, PROTOCOLREG));
  1209.     LocalFree(pr->pszProtocol);
  1210.     LocalFree(pr->pszServer);
  1211.     return 1;
  1212. }
  1213. //
  1214. // _DestroyUrlEcho - DPA callback to free allocated memory
  1215. //
  1216. int CIEDDE::_DestroyUrlEcho(LPVOID p1, LPVOID p2)
  1217. {
  1218.     ASSERT(IS_VALID_STRING_PTR((LPTSTR)p1, -1));
  1219.     LocalFree(p1);
  1220.     return 1;
  1221. }
  1222. //
  1223. // Uninitialize - called when ready to stop IEDDE server
  1224. //
  1225. void CIEDDE::_Uninitialize(void)
  1226. {
  1227.     ENTERPROC(2, TEXT("_Uninitialize()"));
  1228.     _fAutomationReady = FALSE;
  1229.     if (_hdsaWinitem)
  1230.     {
  1231.         if (DSA_GetItemCount(_hdsaWinitem))
  1232.         {
  1233.             //ASSERT(DSA_GetItemCount(_hdsaWinitem)==0);
  1234.             TraceMsg(TF_ERROR, "IEDDE: Browser windows still open on uninitialize");
  1235.             DSA_DestroyCallback(_hdsaWinitem, _DestroyWinitem, 0);
  1236.         }
  1237.         _hdsaWinitem = NULL;
  1238.     }
  1239.     if (_hdsaProtocolHandler)
  1240.     {
  1241.         DSA_DestroyCallback(_hdsaProtocolHandler, _DestroyProtocol, 0);
  1242.         _hdsaProtocolHandler = NULL;
  1243.     }
  1244.     if (_hdpaUrlEcho)
  1245.     {
  1246.         DPA_DestroyCallback(_hdpaUrlEcho, _DestroyUrlEcho, 0);
  1247.         _hdpaUrlEcho = NULL;
  1248.     }
  1249.     if (_fCSInitialized)
  1250.     {
  1251.         DeleteCriticalSection(&_csIEDDE);
  1252.     }
  1253.     EXITPROC(2, TEXT("_Uninitialize!"));
  1254. }
  1255. //
  1256. // _AutomationStarted - called when automation support can be called
  1257. //
  1258. void CIEDDE::_AutomationStarted(void)
  1259. {
  1260.     ENTERPROC(1, TEXT("_AutomationStarted()"));
  1261.     _fAutomationReady = TRUE;
  1262.     EXITPROC(1, TEXT("_AutomationStarted!"));
  1263. }
  1264. //
  1265. // _BeforeNavigate - called before a navigation occurs.
  1266. //
  1267. HRESULT CIEDDE::_BeforeNavigate(LPCTSTR pszURL, BOOL *pfProcessed)
  1268. {
  1269.     ENTERPROC(1, TEXT("_BeforeNavigate(pszURL=>%s<,pfProcessed=%08X)"), pszURL, pfProcessed);
  1270.     SHSTR shstrMsg;
  1271.     HRESULT hr = S_OK;
  1272.     int cProtocols = 0;
  1273.     ENTER_IEDDE_CRIT;
  1274.     if (_hdsaProtocolHandler)
  1275.     {
  1276.         cProtocols = DSA_GetItemCount(_hdsaProtocolHandler);
  1277.     }
  1278.     LEAVE_IEDDE_CRIT;
  1279.     if (cProtocols)
  1280.     {
  1281.         DDETHREADINFO dti;
  1282.         if (_GetDtiFromThread(GetCurrentThreadId(), &dti))
  1283.         {
  1284.             PARSEDURL pu;
  1285.             pu.cbSize = SIZEOF(pu);
  1286.             if (SUCCEEDED(ParseURL(pszURL, &pu)))
  1287.             {
  1288.                 int i;
  1289.                 for (i=0; i<cProtocols; i++)
  1290.                 {
  1291.                     PROTOCOLREG pr;
  1292.                     ENTER_IEDDE_CRIT;
  1293.                     int iResult = DSA_GetItem(_hdsaProtocolHandler, i, &pr);
  1294.                     LEAVE_IEDDE_CRIT;
  1295.                     if (iResult != -1)
  1296.                     {
  1297.                         //
  1298.                         // Check to see if the protocol to navigate
  1299.                         // matches one of our registered protocols.
  1300.                         // We do a case insensitive compare.  Note
  1301.                         // that:
  1302.                         //
  1303.                         //   (1) ParseURL does not null terminate the
  1304.                         //       pu.pszProtocol (its length is stored
  1305.                         //       in pu.cchProtocol).
  1306.                         //
  1307.                         //   (2) pu.pszProtocol is a LPCTSTR so we
  1308.                         //       can't modify the pszProtocol ourselves.
  1309.                         //
  1310.                         //   (3) There is no win32 lstrncmpi() API.
  1311.                         //
  1312.                         // Therefore in order to do a case insensitive
  1313.                         // compare we must copy the pu.pszProtocol into
  1314.                         // a writable buffer at some point.
  1315.                         //
  1316.                         if (lstrlen(pr.pszProtocol) == (int)pu.cchProtocol)
  1317.                         {
  1318.                             shstrMsg.SetStr(pu.pszProtocol, pu.cchProtocol);
  1319.                             if (StrCmpI(pr.pszProtocol, shstrMsg) == 0)
  1320.                             {
  1321.                                 //
  1322.                                 // BUGBUG - use MakeQuotedString here?
  1323.                                 //
  1324.                                 shstrMsg.SetStr(TEXT("""));
  1325.                                 shstrMsg.Append(pszURL);
  1326.                                 shstrMsg.Append(TEXT("",,-1,0,,,,"));
  1327.                                 if (_SendDDEMessageSz(dti.dwDDEInst, pr.pszServer, c_szWWWOpenURL, shstrMsg, XTYP_REQUEST))
  1328.                                 {
  1329.                                     if (pfProcessed)
  1330.                                     {
  1331.                                         *pfProcessed = TRUE;
  1332.                                     }
  1333.                                 }
  1334.                                 else
  1335.                                 {
  1336.                                     TraceMsg(TF_WARNING, "IEDDE: _BeforeNavigate could not DDE to protocol handler");
  1337.                                 }
  1338.                                 break;
  1339.                             }
  1340.                         }
  1341.                     }
  1342.                     else
  1343.                     {
  1344.                         TraceMsg(TF_WARNING, "IEDDE: _BeforeNavigate could not get item from DSA");
  1345.                     }
  1346.                 }
  1347.             }
  1348.             else
  1349.             {
  1350.                 TraceMsg(TF_WARNING, "IEDDE: _BeforeNavigate could not parse URL");
  1351.             }
  1352.         }
  1353.         else
  1354.         {
  1355.             TraceMsg(TF_WARNING, "IEDDE: _BeforeNavigate unable to get thread info, can't use DDE");
  1356.         }
  1357.     }
  1358.     EXITPROC(1, TEXT("_BeforeNavigate=%08X"), hr);
  1359.     return hr;
  1360. }
  1361. //
  1362. // _AfterNavigate - called after a navigation occurs
  1363. //
  1364. HRESULT CIEDDE::_AfterNavigate(LPCTSTR pszURL, HWND hwnd)
  1365. {
  1366.     ENTERPROC(1, TEXT("_AfterNavigate(pszURL=>%s<,hwnd=%08X)"), pszURL, hwnd);
  1367.     int cURLHooks = 0;
  1368.     SHSTR shstrMsg;
  1369.     HRESULT hr = S_OK;
  1370.     ENTER_IEDDE_CRIT;
  1371.     if (_hdpaUrlEcho)
  1372.     {
  1373.         cURLHooks = DPA_GetPtrCount(_hdpaUrlEcho);
  1374.     }
  1375.     LEAVE_IEDDE_CRIT;
  1376.     if (cURLHooks)
  1377.     {
  1378.         SHSTR shstrMime;
  1379.         // BUGBUG (mattsq 1-97)
  1380.         // this is a temporary lie - it should be fixed to use the real mimetype
  1381.         // with something like:
  1382.         //      GetMimeTypeFromUrl(pszURL, shstrMime);
  1383.         // talk to URLMON people
  1384.         shstrMime.SetStr(TEXT("text/html"));
  1385.         DDETHREADINFO dti={0};
  1386.         WINITEM wi;
  1387.         DWORD dwWindowID;
  1388.         if (GetWinitemFromHwnd(hwnd, &wi))
  1389.         {
  1390.             dwWindowID = wi.dwWindowID;
  1391.             wi.pidt->GetDdeThreadInfo(&dti);
  1392.         }
  1393.         else
  1394.         {
  1395.             TraceMsg(TF_WARNING, "IEDDE: _AfterNavigate unable to find browser window ID, using -1");
  1396.             dwWindowID = (DWORD)-1;
  1397.             WINITEM wiThread;
  1398.             if (_GetWinitemFromThread(GetCurrentThreadId(), &wiThread))
  1399.             {
  1400.                 ASSERT(wiThread.pidt);
  1401.                 wiThread.pidt->GetDdeThreadInfo(&dti);
  1402.             }
  1403.             else
  1404.             {
  1405.                 TraceMsg(TF_WARNING, "IEDDE: _AfterNavigate unable to find DDE thread info");
  1406.             }
  1407.         }
  1408.         if (dti.dwDDEInst)
  1409.         {
  1410.             HSZ hszTopic = DdeCreateStringHandle(dti.dwDDEInst, c_szWWWUrlEcho, CP_WINNEUTRAL);
  1411.             if (hszTopic)
  1412.             {
  1413.                 TCHAR szFinish[16];
  1414.                 shstrMsg.SetStr(TEXT("""));                // Quote
  1415.                 shstrMsg.Append(pszURL);                    // URL
  1416.                 shstrMsg.Append(TEXT("",""));             // Quote Comma Quote
  1417.                 shstrMsg.Append(shstrMime);                 // Mime
  1418.                 wnsprintf(szFinish, ARRAYSIZE(szFinish), TEXT("",%d"), dwWindowID);    //
  1419.                 shstrMsg.Append(szFinish);                  // Quote Comma dwWindowID NULL
  1420.                 HSZ hszMsg = DdeCreateStringHandle(dti.dwDDEInst, shstrMsg, CP_WINNEUTRAL);
  1421.                 if (hszMsg)
  1422.                 {
  1423.                     //
  1424.                     // Enumerate in reverse order because calling a hook may destroy it.
  1425.                     //
  1426.                     for (int i=cURLHooks-1; i>=0; --i)
  1427.                     {
  1428.                         ENTER_IEDDE_CRIT;
  1429.                         LPTSTR pszService = (LPTSTR)DPA_GetPtr(_hdpaUrlEcho, i);
  1430.                         LEAVE_IEDDE_CRIT;
  1431.                         if (pszService != NULL)
  1432.                         {
  1433.                             HSZ hszService = DdeCreateStringHandle(dti.dwDDEInst, pszService, CP_WINNEUTRAL);
  1434.                             if (hszService)
  1435.                             {
  1436.                                 if (_SendDDEMessageHsz(dti.dwDDEInst, hszService, hszTopic, hszMsg, XTYP_POKE) == 0)
  1437.                                 {
  1438.                                     TraceMsg(TF_WARNING, "IEDDE: _AfterNavigate could not DDE to URLHook handler");
  1439.                                 }
  1440.                                 DdeFreeStringHandle(dti.dwDDEInst, hszService);
  1441.                             }
  1442.                             else
  1443.                             {
  1444.                                 TraceMsg(TF_WARNING, "IEDDE: _AfterNavigate unable to create hszService");
  1445.                             }
  1446.                         }
  1447.                         else
  1448.                         {
  1449.                             TraceMsg(TF_WARNING, "IEDDE: _AfterNavigate unable to enumerate an URL hook");
  1450.                         }
  1451.                     }
  1452.                     DdeFreeStringHandle(dti.dwDDEInst, hszMsg);
  1453.                 }
  1454.                 else
  1455.                 {
  1456.                     TraceMsg(TF_WARNING, "IEDDE: _AfterNavigate unable to create hszMsg");
  1457.                 }
  1458.                 DdeFreeStringHandle(dti.dwDDEInst, hszTopic);
  1459.             }
  1460.             else
  1461.             {
  1462.                 TraceMsg(TF_WARNING, "IEDDE: _AfterNavigate unable to create hszTopic");
  1463.             }
  1464.         }
  1465.     }
  1466.     EXITPROC(1, TEXT("_AfterNavigate=%08X"), hr);
  1467.     return hr;
  1468. }
  1469. //
  1470. // GetWinitemFromHwnd - return the winitem associated with an hwnd
  1471. //
  1472. BOOL CIEDDE::GetWinitemFromHwnd(HWND hwnd, WINITEM *pwi)
  1473. {
  1474.     BOOL fSuccess = FALSE;
  1475.     ENTERPROC(2, TEXT("GetWinitemFromHwnd(hwnd=%08X,pwi=%08X)"), hwnd, pwi);
  1476.     ENTER_IEDDE_CRIT;
  1477.     if (_hdsaWinitem)
  1478.     {
  1479.         for (int i=0; i<DSA_GetItemCount(_hdsaWinitem); i++)
  1480.         {
  1481.             WINITEM wi;
  1482.             if (DSA_GetItem(_hdsaWinitem, i, &wi) != -1)
  1483.             {
  1484.                 if (wi.hwnd == hwnd)
  1485.                 {
  1486.                     *pwi = wi;
  1487.                     fSuccess = TRUE;
  1488.                     break;
  1489.                 }
  1490.             }
  1491.         }
  1492.     }
  1493.     LEAVE_IEDDE_CRIT;
  1494.     EXITPROC(2, TEXT("GetWinitemFromHwnd=%d"), fSuccess); 
  1495.     return fSuccess;
  1496. }
  1497. //
  1498. // GetWinitemFromWindowID - return the winitem associated with a window ID
  1499. //
  1500. BOOL CIEDDE::GetWinitemFromWindowID(DWORD dwWindowID, WINITEM *pwi)
  1501. {
  1502.     BOOL fSuccess = FALSE;
  1503.     ENTERPROC(3, TEXT("GetWinitemFromWindowID(dwWindowID=%08X,pwi=%08X)"), dwWindowID, pwi);
  1504.     ENTER_IEDDE_CRIT;
  1505.     if (_hdsaWinitem)
  1506.     {
  1507.         for (int i=0; i<DSA_GetItemCount(_hdsaWinitem); i++)
  1508.         {
  1509.             WINITEM wi;
  1510.             if (DSA_GetItem(_hdsaWinitem, i, &wi) != -1)
  1511.             {
  1512.                 if (wi.dwWindowID == dwWindowID)
  1513.                 {
  1514.                     *pwi = wi;
  1515.                     fSuccess = TRUE;
  1516.                     break;
  1517.                 }
  1518.             }
  1519.         }
  1520.     }
  1521.     LEAVE_IEDDE_CRIT;
  1522.     EXITPROC(2, TEXT("GetWinitemFromWindowID=%d"), fSuccess); 
  1523.     return fSuccess;
  1524. }
  1525. //
  1526. // _GetWinitemFromThread - return the first winitem associated with a thread
  1527. //
  1528. BOOL CIEDDE::_GetWinitemFromThread(DWORD dwThreadID, WINITEM *pwi)
  1529. {
  1530.     BOOL fSuccess = FALSE;
  1531.     ENTERPROC(2, TEXT("_GetWinitemFromThread(dwThreadID=%08X,pwi=%08X)"), dwThreadID, pwi);
  1532.     ENTER_IEDDE_CRIT;
  1533.     if (_hdsaWinitem)
  1534.     {
  1535.         for (int i=0; i<DSA_GetItemCount(_hdsaWinitem); i++)
  1536.         {
  1537.             WINITEM wi;
  1538.             if (DSA_GetItem(_hdsaWinitem, i, &wi) != -1)
  1539.             {
  1540.                 if (wi.dwThreadID == dwThreadID)
  1541.                 {
  1542.                     *pwi = wi;
  1543.                     fSuccess = TRUE;
  1544.                     break;
  1545.                 }
  1546.             }
  1547.         }
  1548.     }
  1549.     LEAVE_IEDDE_CRIT;
  1550.     EXITPROC(2, TEXT("_GetWinitemFromThread=%d"), fSuccess); 
  1551.     return fSuccess;
  1552. }
  1553. //
  1554. // _GetDtiFromThread - return the threadinfo associated with a thread
  1555. //
  1556. BOOL CIEDDE::_GetDtiFromThread(DWORD dwThreadID, DDETHREADINFO *pdti)
  1557. {
  1558.     BOOL fSuccess = FALSE;
  1559.     ENTERPROC(2, TEXT("_GetDtiFromThread(dwThreadID=%08X,pdti=%08X)"), dwThreadID, pdti);
  1560.     ENTER_IEDDE_CRIT;
  1561.     WINITEM wi;
  1562.     if (_GetWinitemFromThread(dwThreadID, &wi))
  1563.     {
  1564.         wi.pidt->GetDdeThreadInfo(pdti);
  1565.         fSuccess = TRUE;
  1566.     }
  1567.     else
  1568.     {
  1569.         TraceMsg(TF_WARNING, "IEDDE: _GetDtiFromThread unable to find winitem");
  1570.     }
  1571.     LEAVE_IEDDE_CRIT;
  1572.     EXITPROC(2, TEXT("_GetDtiFromThread=%d"), fSuccess); 
  1573.     return fSuccess;
  1574. }
  1575. //
  1576. // _CreateDdeThreadInfo - Initialize DDE services and names for this thread
  1577. //
  1578. BOOL CIEDDE::_CreateDdeThreadInfo(DDETHREADINFO *pdti)
  1579. {
  1580.     BOOL fSuccess = FALSE;
  1581.     ENTERPROC(2, TEXT("_CreateDdeThreadInfo(pdti=%08X)"), pdti);
  1582.     UINT uiDDE;
  1583.     DDETHREADINFO dti={0};
  1584.     //
  1585.     // Initialize DDEML, register our service.
  1586.     //
  1587.     uiDDE = DdeInitialize(&dti.dwDDEInst, (PFNCALLBACK)DdeCallback,
  1588.                            APPCLASS_STANDARD | CBF_FAIL_ADVISES |
  1589.                            CBF_SKIP_REGISTRATIONS | CBF_SKIP_UNREGISTRATIONS, 0);
  1590.     if (uiDDE == DMLERR_NO_ERROR)
  1591.     {
  1592.         dti.hszReturn = DdeCreateStringHandle(dti.dwDDEInst, c_szReturn, CP_WINNEUTRAL);
  1593.         if (dti.hszReturn)
  1594.         {
  1595.             dti.hszService = DdeCreateStringHandle(dti.dwDDEInst, c_szIExplore, CP_WINNEUTRAL);
  1596.             if (dti.hszService)
  1597.             {
  1598.                 *pdti = dti;
  1599.                 fSuccess = TRUE;
  1600.             }
  1601.             else
  1602.             {
  1603.                 TraceMsg(TF_WARNING, "IEDDE: _CreateDdeThreadInfo unable to convert service");
  1604.             }
  1605.             if (!fSuccess)
  1606.             {
  1607.                 DdeFreeStringHandle(dti.dwDDEInst, dti.hszReturn);
  1608.             }
  1609.         }
  1610.         else
  1611.         {
  1612.             TraceMsg(TF_WARNING, "IEDDE: _CreateDdeThreadInfo unable to convert return");
  1613.         }
  1614.         if (!fSuccess)
  1615.         {
  1616.             DdeUninitialize(dti.dwDDEInst);
  1617.         }
  1618.     }
  1619.     else
  1620.     {
  1621.         TraceMsg(TF_WARNING, "IEDDE: _CreateDdeThreadInfo unable to init DDE");
  1622.     }
  1623.     EXITPROC(2, TEXT("_CreateDdeThreadInfo=%d"), fSuccess);
  1624.     return fSuccess;
  1625. }
  1626. //
  1627. // _DestroyDdeThreadInfo - Free up any resources in a dti structure.
  1628. //
  1629. void CIEDDE::_DestroyDdeThreadInfo(DDETHREADINFO *pdti)
  1630. {
  1631.     ENTERPROC(2, TEXT("_DestroyDdeThreadInfo(pdti=%08X)"), pdti);
  1632.     if (pdti->hddNameService)
  1633.     {
  1634.         ASSERT(pdti->hszService);
  1635.         DdeNameService(pdti->dwDDEInst, pdti->hszService, 0, DNS_UNREGISTER);
  1636.         pdti->hddNameService = 0;
  1637.     }
  1638.     if (pdti->hszService)
  1639.     {
  1640.         DdeFreeStringHandle(pdti->dwDDEInst, pdti->hszService);
  1641.         pdti->hszService = 0;
  1642.     }
  1643.     if (pdti->hszReturn)
  1644.     {
  1645.         DdeFreeStringHandle(pdti->dwDDEInst, pdti->hszReturn);
  1646.         pdti->hszReturn = 0;
  1647.     }
  1648.     if (pdti->dwDDEInst)
  1649.     {
  1650.         DdeUninitialize(pdti->dwDDEInst);
  1651.         pdti->dwDDEInst = 0;
  1652.     }
  1653.     EXITPROC(2, TEXT("_DestroyDdeThreadInfo!"));
  1654.     return;
  1655. }
  1656. //
  1657. // _AddWinitem - adds a winitem to _hdsaWinitem
  1658. //
  1659. BOOL CIEDDE::_AddWinitem(WINITEM *pwi)
  1660. {
  1661.     BOOL fSuccess = FALSE;
  1662.     ENTERPROC(2, TEXT("_AddWinitem(pwi=%08X)"), pwi);
  1663.     ENTER_IEDDE_CRIT;
  1664.     if (!_hdsaWinitem)
  1665.     {
  1666.         _hdsaWinitem = DSA_Create(SIZEOF(WINITEM), DXA_GROWTH_AMOUNT);
  1667.     }
  1668.     if (_hdsaWinitem)
  1669.     {
  1670.         if (DSA_AppendItem(_hdsaWinitem, pwi) != -1)
  1671.         {
  1672.             fSuccess = TRUE;
  1673.         }
  1674.         else
  1675.         {
  1676.             TraceMsg(TF_WARNING, "IEDDE: _AddWinitem could not append an item");
  1677.         }
  1678.     }
  1679.     else
  1680.     {
  1681.         TraceMsg(TF_WARNING, "IEDDE: _AddWinitem could not create hdsa");
  1682.     }
  1683.     LEAVE_IEDDE_CRIT;
  1684.     EXITPROC(2, TEXT("_AddWinitem=%d"), fSuccess);
  1685.     return fSuccess;
  1686. }
  1687. //
  1688. // _UpdateWinitem - updates a winitem based on the dwWindowID.
  1689. //
  1690. BOOL CIEDDE::_UpdateWinitem(WINITEM *pwi)
  1691. {
  1692.     BOOL fSuccess = FALSE;
  1693.     ENTERPROC(2, TEXT("_UpdateWinitem(pwi=%08X)"), pwi);
  1694.     ENTER_IEDDE_CRIT;
  1695.     if (_hdsaWinitem)
  1696.     {
  1697.         int cItems = DSA_GetItemCount(_hdsaWinitem);
  1698.         for (int i=0; i<cItems; i++)
  1699.         {
  1700.             WINITEM wi;
  1701.             if (DSA_GetItem(_hdsaWinitem, i, &wi) != -1)
  1702.             {
  1703.                 if (wi.dwWindowID == pwi->dwWindowID)
  1704.                 {
  1705.                     if (DSA_SetItem(_hdsaWinitem, i, pwi))
  1706.                     {
  1707.                         fSuccess = TRUE;
  1708.                     }
  1709.                     else
  1710.                     {
  1711.                         TraceMsg(TF_WARNING, "IEDDE: _UpdateWinitem could not update an item");
  1712.                     }
  1713.                     break;
  1714.                 }
  1715.             }
  1716.             else
  1717.             {
  1718.                 TraceMsg(TF_WARNING, "IEDDE: _UpdateWinitem could not get an item");
  1719.             }
  1720.         }
  1721.     }
  1722.     LEAVE_IEDDE_CRIT;
  1723.     EXITPROC(2, TEXT("_UpdateWinitem=%d"), fSuccess);
  1724.     return fSuccess;
  1725. }
  1726. //
  1727. // AddUrlEcho - adds an UrlEcho entry to the dpa
  1728. //
  1729. BOOL CIEDDE::AddUrlEcho(LPCTSTR pszUrlEcho)
  1730. {
  1731.     BOOL fSuccess = FALSE;
  1732.     ENTERPROC(2, TEXT("AddUrlEcho(pszUrlEcho=>%s<)"), pszUrlEcho);
  1733.     ENTER_IEDDE_CRIT;
  1734.     if (!_hdpaUrlEcho)
  1735.     {
  1736.         _hdpaUrlEcho = DPA_Create(DXA_GROWTH_AMOUNT);
  1737.     }
  1738.     if (_hdpaUrlEcho)
  1739.     {
  1740.         if (DPA_AppendPtr(_hdpaUrlEcho, (LPVOID)pszUrlEcho) != -1)
  1741.         {
  1742.             fSuccess = TRUE;
  1743.         }
  1744.         else
  1745.         {
  1746.             TraceMsg(TF_WARNING, "IEDDE: AddUrlEcho unable to append a ptr");
  1747.         }
  1748.     }
  1749.     else
  1750.     {
  1751.         TraceMsg(TF_WARNING, "IEDDE: AddUrlEcho unable to create a dpa");
  1752.     }
  1753.     LEAVE_IEDDE_CRIT;
  1754.     EXITPROC(2, TEXT("AddUrlEcho=%d"), fSuccess);
  1755.     return fSuccess;
  1756. }
  1757. //
  1758. // RemoveUrlEcho - remove an UrlEcho entry from the dpa
  1759. //
  1760. BOOL CIEDDE::RemoveUrlEcho(LPCTSTR pszUrlEcho)
  1761. {
  1762.     BOOL fSuccess = FALSE;
  1763.     ENTERPROC(2, TEXT("RemoveUrlEcho(pszUrlEcho=>%s<)"), pszUrlEcho);
  1764.     ENTER_IEDDE_CRIT;
  1765.     if (_hdpaUrlEcho)
  1766.     {
  1767.         for (int i=0; i<DPA_GetPtrCount(_hdpaUrlEcho); i++)
  1768.         {
  1769.             LPTSTR pszList = (LPTSTR)DPA_GetPtr(_hdpaUrlEcho, i);
  1770.             if (pszList)
  1771.             {
  1772.                 if (StrCmpI(pszList, pszUrlEcho) == 0)
  1773.                 {
  1774.                     DPA_DeletePtr(_hdpaUrlEcho, i);
  1775.                     LocalFree((HANDLE)pszList);
  1776.                     fSuccess = TRUE;
  1777.                     break;
  1778.                 }
  1779.             }
  1780.             else
  1781.             {
  1782.                 TraceMsg(TF_ALWAYS, "IEDDE: RemoveUrlEcho unable to get dpa ptr");
  1783.             }
  1784.         }
  1785.         if (!fSuccess)
  1786.         {
  1787.             TraceMsg(TF_WARNING, "IEDDE: RemoveUrlEcho unable to find server");
  1788.         }
  1789.     }
  1790.     else
  1791.     {
  1792.         TraceMsg(TF_WARNING, "IEDDE: RemoveUrlEcho unable to find dpa");
  1793.     }
  1794.     LEAVE_IEDDE_CRIT;
  1795.     EXITPROC(2, TEXT("RemoveUrlEcho=%d"), fSuccess);
  1796.     return fSuccess;
  1797. }
  1798. //
  1799. // AddProtocolHandler - add a PROTOCOLREG entry to the dsa
  1800. //
  1801. BOOL CIEDDE::AddProtocolHandler(LPCTSTR pszServer, LPCTSTR pszProtocol)
  1802. {
  1803.     BOOL fSuccess = FALSE;
  1804.     ENTERPROC(2, TEXT("AddProtocolHandler(pszServer=>%s<,pszProtocol=>%s<)"), pszServer, pszProtocol);
  1805.     ENTER_IEDDE_CRIT;
  1806.     PROTOCOLREG pr;
  1807.     //
  1808.     // First, see if anybody else grabbed the protocol first.
  1809.     //
  1810.     BOOL fFoundHandler = FALSE;
  1811.     if (_hdsaProtocolHandler)
  1812.     {
  1813.         for (int i=0; i<DSA_GetItemCount(_hdsaProtocolHandler); i++)
  1814.         {
  1815.             if (DSA_GetItem(_hdsaProtocolHandler, i, &pr) != -1)
  1816.             {
  1817.                 if (StrCmpI(pr.pszProtocol, pszProtocol) == 0)
  1818.                 {
  1819.                     TraceMsg(TF_WARNING, "IEDDE: AddProtocolHandler already has a handler");
  1820.                     fFoundHandler = TRUE;
  1821.                     break;
  1822.                 }
  1823.             }
  1824.             else
  1825.             {
  1826.                 TraceMsg(TF_WARNING, "IEDDE: AddProtocolHandler unable to get an item");
  1827.             }
  1828.         }
  1829.     }
  1830.     if (!fFoundHandler)
  1831.     {
  1832.         if (!_hdsaProtocolHandler)
  1833.         {
  1834.             _hdsaProtocolHandler = DSA_Create(SIZEOF(PROTOCOLREG), DXA_GROWTH_AMOUNT);
  1835.         }
  1836.         if (_hdsaProtocolHandler)
  1837.         {
  1838.             pr.pszServer = StrDup(pszServer);
  1839.             if (pr.pszServer)
  1840.             {
  1841.                 pr.pszProtocol = StrDup(pszProtocol);
  1842.                 if (pr.pszProtocol)
  1843.                 {
  1844.                     if (DSA_AppendItem(_hdsaProtocolHandler, &pr) != -1)
  1845.                     {
  1846.                         fSuccess = TRUE;
  1847.                     }
  1848.                     else
  1849.                     {
  1850.                         TraceMsg(TF_WARNING, "IEDDE: AddProtocolHandler unable to append to dsa");
  1851.                     }
  1852.                     if (!fSuccess)
  1853.                     {
  1854.                         LocalFree((HANDLE)pr.pszProtocol);
  1855.                     }
  1856.                 }
  1857.                 else
  1858.                 {
  1859.                     TraceMsg(TF_WARNING, "IEDDE: AddProtocolHandler unable to dup protocol");
  1860.                 }
  1861.                 if (!fSuccess)
  1862.                 {
  1863.                     LocalFree((HANDLE)pr.pszServer);
  1864.                 }
  1865.             }
  1866.             else
  1867.             {
  1868.                 TraceMsg(TF_WARNING, "IEDDE: AddProtocolHandler unable to dup server");
  1869.             }
  1870.         }
  1871.         else
  1872.         {
  1873.             TraceMsg(TF_WARNING, "IEDDE: AddProtocolHandler unable to create dsa");
  1874.         }
  1875.     }
  1876.     LEAVE_IEDDE_CRIT;
  1877.     EXITPROC(2, TEXT("AddProtocolHandler=%d"), fSuccess);
  1878.     return fSuccess;
  1879. }
  1880. //
  1881. // RemoveProtocolHandler - removes a PROTOCOLREG item from the dsa
  1882. //
  1883. BOOL CIEDDE::RemoveProtocolHandler(LPCTSTR pszServer, LPCTSTR pszProtocol)
  1884. {
  1885.     BOOL fSuccess = FALSE;
  1886.     ENTERPROC(2, TEXT("RemoveProtocolHandler(pszServer=>%s<,pszProtocol=>%s<)"), pszServer, pszProtocol);
  1887.     ENTER_IEDDE_CRIT;
  1888.     if (_hdsaProtocolHandler)
  1889.     {
  1890.         for (int i=0; i<DSA_GetItemCount(_hdsaProtocolHandler); i++)
  1891.         {
  1892.             PROTOCOLREG pr;
  1893.             if (DSA_GetItem(_hdsaProtocolHandler, i, &pr) != -1)
  1894.             {
  1895.                 if (StrCmpI(pr.pszProtocol, pszProtocol) == 0)
  1896.                 {
  1897.                     if (StrCmpI(pr.pszServer, pszServer) == 0)
  1898.                     {
  1899.                         if (DSA_DeleteItem(_hdsaProtocolHandler, i) != -1)
  1900.                         {
  1901.                             LocalFree((HANDLE)pr.pszServer);
  1902.                             LocalFree((HANDLE)pr.pszProtocol);
  1903.                             fSuccess = TRUE;
  1904.                         }
  1905.                         else
  1906.                         {
  1907.                             TraceMsg(TF_WARNING, "IEDDE: RemoveProtocolHandler unable to remove item");
  1908.                         }
  1909.                     }
  1910.                     else
  1911.                     {
  1912.                         TraceMsg(TF_WARNING, "IEDDE: RemoveProtocolHandler says server didn't match");
  1913.                     }
  1914.                     break;
  1915.                 }
  1916.             }
  1917.             else
  1918.             {
  1919.                 TraceMsg(TF_WARNING, "IEDDE: RemoveProtocolHandler unable to get item");
  1920.             }
  1921.         }
  1922.         if (!fSuccess)
  1923.         {
  1924.             TraceMsg(TF_WARNING, "IEDDE: RemoveProtocolHandler unable to complete mission");
  1925.         }
  1926.     }
  1927.     else
  1928.     {
  1929.         TraceMsg(TF_WARNING, "IEDDE: RemoveProtocolHandler can't find the dsa");
  1930.     }
  1931.     LEAVE_IEDDE_CRIT;
  1932.     EXITPROC(2, TEXT("RemoveProtocolHandler=%d"), fSuccess);
  1933.     return fSuccess;
  1934. }
  1935. //
  1936. // _DeleteWinitemByHwnd - removes a winitem from _hdsaWinitem
  1937. //
  1938. BOOL CIEDDE::_DeleteWinitemByHwnd(HWND hwnd, WINITEM *pwi)
  1939. {
  1940.     BOOL fSuccess = FALSE;
  1941.     ENTERPROC(2, TEXT("_DeleteWinitemByHwnd(hwnd=%08X,pwi=%08X)"), hwnd, pwi);
  1942.     ENTER_IEDDE_CRIT;
  1943.     if (_hdsaWinitem)
  1944.     {
  1945.         for (int i=0; i<DSA_GetItemCount(_hdsaWinitem); i++)
  1946.         {
  1947.             WINITEM wi;
  1948.             if (DSA_GetItem(_hdsaWinitem, i, &wi) != -1)
  1949.             {
  1950.                 if (wi.hwnd == hwnd)
  1951.                 {
  1952.                     if (DSA_DeleteItem(_hdsaWinitem, i) != -1)
  1953.                     {
  1954.                         *pwi = wi;
  1955.                         fSuccess = TRUE;
  1956.                     }
  1957.                     else
  1958.                     {
  1959.                         TraceMsg(TF_WARNING, "IEDDE: _DeleteWinitemByHwnd could note delete an item");
  1960.                     }
  1961.                     break;
  1962.                 }
  1963.             }
  1964.             else
  1965.             {
  1966.                 TraceMsg(TF_WARNING, "IEDDE: _DeleteWinitemByHwnd could note get an item");
  1967.             }
  1968.         }
  1969.     }
  1970.     else
  1971.     {
  1972.         TraceMsg(TF_WARNING, "IEDDE: _DeleteWinitemByHwnd has no _hdsaWinitem");
  1973.     }
  1974.     LEAVE_IEDDE_CRIT;
  1975.     EXITPROC(2, TEXT("_DeleteWinitemByHwnd=%d"), fSuccess);
  1976.     return fSuccess;
  1977. }
  1978. //
  1979. // _NewWindow - Add a browser window to the internal list
  1980. //
  1981. BOOL CIEDDE::_NewWindow(HWND hwnd)
  1982. {
  1983.     BOOL fSuccess = FALSE;
  1984.     ENTERPROC(1, TEXT("NewWindow(hwnd=%08X)"), hwnd);
  1985.     ASSERT(IS_VALID_HANDLE(hwnd, WND));
  1986.     ENTER_IEDDE_CRIT;
  1987.     WINITEM wi;
  1988.     if (GetWinitemFromHwnd(hwnd, &wi) == FALSE)
  1989.     {
  1990.         CIEDDEThread *pidt = new CIEDDEThread();
  1991.         if (pidt)
  1992.         {
  1993.             DDETHREADINFO dti = {0};
  1994.             DWORD dwThreadID = GetCurrentThreadId();
  1995.             WINITEM wi;
  1996.             BOOL fCreatedDTI = FALSE;
  1997.             if (_GetWinitemFromThread(dwThreadID, &wi))
  1998.             {
  1999.                 wi.pidt->GetDdeThreadInfo(&dti);
  2000.             }
  2001.             else
  2002.             {
  2003.                 LEAVE_IEDDE_CRIT;
  2004.                 _CreateDdeThreadInfo(&dti);
  2005.                 ENTER_IEDDE_CRIT;
  2006.                 fCreatedDTI = TRUE;
  2007.             }
  2008.             if (dti.dwDDEInst)
  2009.             {
  2010.                 static DWORD dwNextWindowID = 1;
  2011.                 pidt->SetDdeThreadInfo(&dti);
  2012.                 wi.dwThreadID = dwThreadID;
  2013.                 wi.pidt = pidt;
  2014.                 wi.hwnd = hwnd;
  2015.                 wi.dwWindowID = dwNextWindowID++;
  2016.                 if (_AddWinitem(&wi))
  2017.                 {
  2018.                     //
  2019.                     // Now that we have a (partial) winitem in the winitem
  2020.                     // database, we can register our name service.  If we
  2021.                     // registered any sooner, there is a risk that an app
  2022.                     // will try to connect to us while we are registering,
  2023.                     // and we will fail the connect because the winitem
  2024.                     // is not in the registry yet.
  2025.                     //
  2026.                     LEAVE_IEDDE_CRIT;
  2027.                     dti.hddNameService = DdeNameService(dti.dwDDEInst, dti.hszService, 0, DNS_REGISTER);
  2028.                     ENTER_IEDDE_CRIT;
  2029.                     //
  2030.                     // Now that we have hddNameService, we can update the
  2031.                     // winitem in the database.
  2032.                     //
  2033.                     if (dti.hddNameService)
  2034.                     {
  2035.                         pidt->SetDdeThreadInfo(&dti);
  2036.                         if (_UpdateWinitem(&wi))
  2037.                         {
  2038.                             fSuccess = TRUE;
  2039.                         }
  2040.                         else
  2041.                         {
  2042.                             TraceMsg(TF_WARNING, "IEDDE: _NewWindow unable to update a win item");
  2043.                         }
  2044.                     }
  2045.                     else
  2046.                     {
  2047.                         TraceMsg(TF_WARNING, "IEDDE: _NewWindow unable to register service");
  2048.                     }
  2049.                 }
  2050.                 else
  2051.                 {
  2052.                     TraceMsg(TF_WARNING, "IEDDE: _NewWindow could not append win item");
  2053.                 }
  2054.                 if (!fSuccess && fCreatedDTI)
  2055.                 {
  2056.                     LEAVE_IEDDE_CRIT;
  2057.                     _DestroyDdeThreadInfo(&dti);
  2058.                     ENTER_IEDDE_CRIT;
  2059.                 }
  2060.             }
  2061.             else
  2062.             {
  2063.                 TraceMsg(TF_WARNING, "IEDDE: _NewWindow could not get/create dde thread info");
  2064.             }
  2065.             if (!fSuccess)
  2066.             {
  2067.                 delete pidt;
  2068.             }
  2069.         }
  2070.         else
  2071.         {
  2072.             TraceMsg(TF_WARNING, "IEDDE: _NewWindow could not create iedde thread object");
  2073.         }
  2074.     }
  2075.     else
  2076.     {
  2077.         TraceMsg(TF_WARNING, "IEDDE: _NewWindow says window already registered?!?");
  2078.     }
  2079.     LEAVE_IEDDE_CRIT;
  2080.     EXITPROC(1, TEXT("_NewWindow=%d"), fSuccess);
  2081.     return fSuccess;
  2082. }
  2083. //
  2084. // _WindowDestroyed - Remove a browser window from the internal list
  2085. //
  2086. BOOL CIEDDE::_WindowDestroyed(HWND hwnd)
  2087. {
  2088.     BOOL fSuccess = FALSE;
  2089.     ENTERPROC(1, TEXT("_WindowDestroyed(hwnd=%08X)"), hwnd);
  2090.     ENTER_IEDDE_CRIT;
  2091.     WINITEM wi;
  2092.     if (_DeleteWinitemByHwnd(hwnd, &wi))
  2093.     {
  2094.         fSuccess = TRUE;
  2095.         ASSERT(wi.pidt);
  2096.         WINITEM wiThread;
  2097.         if (_GetWinitemFromThread(wi.dwThreadID, &wiThread) == FALSE)
  2098.         {
  2099.             if (wi.dwThreadID == GetCurrentThreadId())
  2100.             {
  2101.                 DDETHREADINFO dti;
  2102.                 wi.pidt->GetDdeThreadInfo(&dti);
  2103.                 // Don't hold onto critical section while doing this...
  2104.                 LEAVE_IEDDE_CRIT;
  2105.                 _DestroyDdeThreadInfo(&dti);
  2106.                 ENTER_IEDDE_CRIT;
  2107.             }
  2108.             else
  2109.             {
  2110.                 TraceMsg(TF_WARNING, "IEDDE: _WindowDestroyed called on wrong thread");
  2111.             }
  2112.         }
  2113.         delete wi.pidt;
  2114.     }
  2115.     else
  2116.     {
  2117.         TraceMsg(TF_WARNING, "IEDDE: _WindowDestroyed could not find hwnd");
  2118.     }
  2119.     LEAVE_IEDDE_CRIT;
  2120.     EXITPROC(1, TEXT("_WindowDestroyed=%d"), fSuccess);
  2121.     return fSuccess;
  2122. }
  2123. //
  2124. // IEDDE_ functions are those exported for other parts of shdocvw to call.
  2125. // They pretty much just call the equivalent function in g_pIEDDE.
  2126. //
  2127. BOOL IEDDE_Initialize(void)
  2128. {
  2129.     BOOL fRet = FALSE;
  2130.     ENTERPROC(2, TEXT("IEDDE_Initialize()"));
  2131.     if (g_pIEDDE == NULL)
  2132.     {
  2133.         g_pIEDDE = new CIEDDE;
  2134.         if (g_pIEDDE)
  2135.         {
  2136.             fRet = g_pIEDDE->_Initialize();
  2137.         }
  2138.         else
  2139.         {
  2140.             TraceMsg(TF_WARNING, "IEDDE: IEDDE_Initialize could not allocate an IEDDE object");
  2141.         }
  2142.     }
  2143.     else
  2144.     {
  2145.         TraceMsg(TF_WARNING, "IEDDE: IEDDE_Initialize says already initialized");
  2146.     }
  2147.     EXITPROC(2, TEXT("IEDDE_Initialize=%d"), fRet);
  2148.     return fRet;
  2149. }
  2150. void IEDDE_Uninitialize(void)
  2151. {
  2152.     ENTERPROC(2, TEXT("IEDDE_Uninitialize()"));
  2153.     if (g_pIEDDE)
  2154.     {
  2155.         g_pIEDDE->_Uninitialize();
  2156.         delete g_pIEDDE;
  2157.         g_pIEDDE = NULL;
  2158.     }
  2159.     else
  2160.     {
  2161.         TraceMsg(TF_WARNING, "IEDDE: IEDDE_Uninitialize has no IEDDE object");
  2162.     }
  2163.     EXITPROC(2, TEXT("IEDDE_Uninitialize!"));
  2164. }
  2165. void IEDDE_AutomationStarted(void)
  2166. {
  2167.     ENTERPROC(2, TEXT("IEDDE_AutomationStarted()"));
  2168.     if (g_pIEDDE)
  2169.     {
  2170.         g_pIEDDE->_AutomationStarted();
  2171.     }
  2172.     else
  2173.     {
  2174.         TraceMsg(TF_WARNING, "IEDDE: IEDDE_AutomationStarted has no IEDDE object");
  2175.     }
  2176.     EXITPROC(2, TEXT("IEDDE_AutomationStarted!"));
  2177. }
  2178. HRESULT IEDDE_BeforeNavigate(LPCWSTR pwszURL, BOOL *pfCanceled)
  2179. {
  2180.     HRESULT hr = E_FAIL;
  2181.     ENTERPROC(2, TEXT("IEDDE_BeforeNavigate(pwszURL=%08X,pfCanceled=%08X)"), pwszURL, pfCanceled);
  2182.     if (g_pIEDDE)
  2183.     {
  2184.         LPCTSTR pszURL;
  2185.         pszURL = pwszURL;
  2186.         if (pszURL)
  2187.         {
  2188.             hr = g_pIEDDE->_BeforeNavigate(pszURL, pfCanceled);
  2189.         }
  2190.     }
  2191.     else
  2192.     {
  2193.         TraceMsg(TF_WARNING, "IEDDE: IEDDE_BeforeNavigate has no IEDDE object");
  2194.     }
  2195.     EXITPROC(2, TEXT("IEDDE_BeforeNavigate=%08X"), hr);
  2196.     return hr;
  2197. }
  2198. HRESULT IEDDE_AfterNavigate(LPCWSTR pwszURL, HWND hwnd)
  2199. {
  2200.     HRESULT hr = E_FAIL;
  2201.     ENTERPROC(2, TEXT("IEDDE_AfterNavigate(pwszURL=%08X,hwnd=%08X)"), pwszURL, hwnd);
  2202.     if (g_pIEDDE)
  2203.     {
  2204.         LPCTSTR pszURL;
  2205.         pszURL = pwszURL;
  2206.         if (pszURL)
  2207.         {
  2208.             hr = g_pIEDDE->_AfterNavigate(pszURL, hwnd);
  2209.         }
  2210.     }
  2211.     else
  2212.     {
  2213.         TraceMsg(TF_WARNING, "IEDDE: IEDDE_AfterNavigate has no IEDDE object");
  2214.     }
  2215.     EXITPROC(2, TEXT("IEDDE_AfterNavigate=%08X"), hr);
  2216.     return hr;
  2217. }
  2218. BOOL IEDDE_NewWindow(HWND hwnd)
  2219. {
  2220.     BOOL fRet = FALSE;
  2221.     ENTERPROC(2, TEXT("IEDDE_NewWindow(hwnd=%08X)"), hwnd);
  2222.     if (g_pIEDDE)
  2223.     {
  2224.         fRet = g_pIEDDE->_NewWindow(hwnd);
  2225.     }
  2226.     else
  2227.     {
  2228.         TraceMsg(TF_WARNING, "IEDDE: IEDDE_NewWindow has no IEDDE object");
  2229.     }
  2230.     EXITPROC(2, TEXT("IEDDE_NewWindow=%d"), fRet);
  2231.     return fRet;
  2232. }
  2233. BOOL IEDDE_WindowDestroyed(HWND hwnd)
  2234. {
  2235.     BOOL fRet = FALSE;
  2236.     ENTERPROC(2, TEXT("IEDDE_WindowDestroyed(hwnd=%08X)"), hwnd);
  2237.     if (g_pIEDDE)
  2238.     {
  2239.         fRet = g_pIEDDE->_WindowDestroyed(hwnd);
  2240.     }
  2241.     else
  2242.     {
  2243.         TraceMsg(TF_WARNING, "IEDDE: IEDDE_WindowDestroyed has no IEDDE object");
  2244.     }
  2245.     EXITPROC(2, TEXT("IEDDE_WindowDestroyed=%d"), fRet);
  2246.     return fRet;
  2247. }
  2248. #ifdef DEBUG
  2249. //
  2250. // BUGBUG - Move g_dwIEDDETrace into ccshell.ini to prevent recompiles.
  2251. //
  2252. DWORD g_dwIEDDETrace = 0;
  2253. static DWORD g_dwIndent = 0;
  2254. static const TCHAR c_szDotDot[] = TEXT("..");
  2255. #define MAX_INDENTATION_VALUE   0x10
  2256. void EnterProc(DWORD dwTraceLevel, LPTSTR szFmt, ...)
  2257. {
  2258.     TCHAR szOutput[1000];
  2259.     va_list arglist;
  2260.     if (dwTraceLevel <= g_dwIEDDETrace)
  2261.     {
  2262.         szOutput[0] = TEXT('');
  2263.         for (DWORD i=0; i<g_dwIndent; i++)
  2264.         {
  2265.             StrCatBuff(szOutput, c_szDotDot, ARRAYSIZE(szOutput));
  2266.         }
  2267.         va_start(arglist, szFmt);
  2268.         wvnsprintf(szOutput + lstrlen(szOutput), ARRAYSIZE(szOutput) - lstrlen(szOutput), szFmt, arglist);
  2269.         va_end(arglist);
  2270.         TraceMsg(TF_ALWAYS, "%s", szOutput);
  2271.         // This value can get out of hand if EnterProc and ExitProc
  2272.         // calls do not match. This can trash the stack.
  2273.         if(g_dwIndent < MAX_INDENTATION_VALUE)
  2274.             g_dwIndent++;
  2275.     }
  2276. }
  2277. void ExitProc(DWORD dwTraceLevel, LPTSTR szFmt, ...)
  2278. {
  2279.     TCHAR szOutput[1000];
  2280.     va_list arglist;
  2281.     if (dwTraceLevel <= g_dwIEDDETrace)
  2282.     {
  2283.         // This can happen if the EnterProc and 
  2284.         // ExitProc calls do not match.
  2285.         if(g_dwIndent > 0)
  2286.             g_dwIndent--;
  2287.         szOutput[0] = TEXT('');
  2288.         for (DWORD i=0; i<g_dwIndent; i++)
  2289.         {
  2290.             StrCatBuff(szOutput, c_szDotDot, ARRAYSIZE(szOutput));
  2291.         }
  2292.         va_start(arglist, szFmt);
  2293.         wvnsprintf(szOutput + lstrlen(szOutput), ARRAYSIZE(szOutput) - lstrlen(szOutput), szFmt, arglist);
  2294.         va_end(arglist);
  2295.         TraceMsg(TF_ALWAYS, "%s", szOutput);
  2296.     }
  2297. }
  2298. #endif