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

Windows Kernel

Development Platform:

Visual C++

  1. #include "iexplore.h"
  2. #include "rcids.h"
  3. #include "shlwapi.h"
  4. #include <platform.h>
  5. #ifdef UNIX
  6. #include "unixstuff.h"
  7. #endif
  8. static const TCHAR c_szBrowseNewProcessReg[] = REGSTR_PATH_EXPLORER TEXT("\BrowseNewProcess");
  9. static const TCHAR c_szBrowseNewProcess[] = TEXT("BrowseNewProcess");
  10. int WinMainT(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpszCmdLine, int nCmdShow);
  11. STDAPI_(int) ModuleEntry(void)
  12. {
  13.     int i;
  14.     STARTUPINFOA si;
  15. #ifdef UNICODE
  16.     LPTSTR pszCmdLine = GetCommandLine();
  17. #else
  18.     // for multibyte should make it unsigned
  19.     BYTE * pszCmdLine = (BYTE *)GetCommandLine();
  20. #endif
  21. #if defined(UNIX) 
  22.     // IEUNIX: On solaris we are getting out of file handles with new code pages added to mlang
  23.     // causing more nls files to be mmapped.
  24.     INCREASE_FILEHANDLE_LIMIT;
  25. #endif
  26.     //
  27.     // We don't want the "No disk in drive X:" requesters, so we set
  28.     // the critical error mask such that calls will just silently fail
  29.     //
  30.     SetErrorMode(SEM_FAILCRITICALERRORS);
  31.     if(StopWatchMode() & SPMODE_BROWSER)  // Used to get the start of browser total download time
  32.     {
  33.         StopWatch_Start(SWID_BROWSER_FRAME, TEXT("Browser Frame Start"), SPMODE_BROWSER | SPMODE_DEBUGOUT);
  34.     }
  35.     
  36.     if ( *pszCmdLine == TEXT('"') ) {
  37.         /*
  38.          * Scan, and skip over, subsequent characters until
  39.          * another double-quote or a null is encountered.
  40.          */
  41.         while ( *++pszCmdLine && (*pszCmdLine
  42.              != TEXT('"')) );
  43.         /*
  44.          * If we stopped on a double-quote (usual case), skip
  45.          * over it.
  46.          */
  47.         if ( *pszCmdLine == TEXT('"') )
  48.             pszCmdLine++;
  49.     }
  50.     else {
  51.         while (*pszCmdLine > TEXT(' '))
  52.             pszCmdLine++;
  53.     }
  54.     /*
  55.      * Skip past any white space preceeding the second token.
  56.      */
  57.     while (*pszCmdLine && (*pszCmdLine <= TEXT(' '))) {
  58.         pszCmdLine++;
  59.     }
  60.     si.dwFlags = 0;
  61.     si.cb = sizeof(si);
  62.     GetStartupInfoA(&si);
  63.     i = WinMainT(GetModuleHandle(NULL), NULL, (LPTSTR)pszCmdLine,
  64.                    si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
  65. #ifndef UNIX  
  66.     ExitThread(i);  // We only come here when we are not the shell...
  67. #else
  68. // there seem to be some desirable side effect calling ExitThread on Windows
  69.     ExitProcess(i); 
  70. #endif
  71.     return i;
  72. }
  73. //
  74. // Create a unique event name
  75. //
  76. HANDLE AppendEvent(COPYDATASTRUCT *pcds)
  77. {
  78.     static DWORD dwNextID = 0;
  79.     TCHAR szEvent[MAX_IEEVENTNAME];
  80.     wsprintf(szEvent, "IE-%08X-%08X", GetCurrentThreadId(), dwNextID++);
  81.     HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, szEvent);
  82.     if (hEvent)
  83.     {
  84.         //
  85.         // Put the (UNICODE) event name at the end of the cds data
  86.         //
  87.         LPWSTR pwszBufferEvent = (LPWSTR)(((BYTE *)pcds->lpData) + pcds->cbData);
  88. #ifdef UNICODE
  89.         lstrcpy(pwszBufferEvent, szEvent);
  90. #else
  91.         MultiByteToWideChar(CP_ACP, 0, szEvent, -1, pwszBufferEvent, ARRAYSIZE(szEvent));
  92. #endif
  93.         pcds->cbData += (lstrlenW(pwszBufferEvent) + 1) * sizeof(WCHAR);
  94.     }
  95.     return hEvent;
  96. }
  97. BOOL IsCommandSwitch(LPTSTR lpszCmdLine, LPTSTR pszSwitch, BOOL fRemoveSwitch)
  98. {
  99.     LPTSTR lpsz;
  100.     
  101.     if ((lpsz=StrStrI(lpszCmdLine, pszSwitch)) && (lpsz == lpszCmdLine))
  102.     {
  103.         int cch = lstrlen(pszSwitch);
  104.         if (*(lpsz+cch) == 0 || *(lpsz+cch) == TEXT(' '))
  105.         {
  106.             while (*(lpsz+cch) == TEXT(' '))
  107.                 cch++;
  108.             if (fRemoveSwitch)
  109.             {
  110.                 // Remove the switch by copying everything up.
  111.                 *lpsz=0;
  112.                 lstrcat(lpsz, lpsz+cch);
  113.             }
  114.             return TRUE;
  115.         }
  116.     } 
  117.     return FALSE;
  118. }
  119. BOOL CheckForNeedingAppCompatWindow(void)
  120. {
  121.     // Which I could simply get the Process of who spawned me.  For now
  122.     // try hack to get the foreground window and go from there...
  123.     TCHAR szClassName[80];
  124.     HWND hwnd = GetForegroundWindow();
  125.     if (hwnd && GetClassName(hwnd, szClassName, ARRAYSIZE(szClassName)) > 0)
  126.     {
  127.         if (lstrcmpi(szClassName, TEXT("MauiFrame")) == 0)
  128.             return TRUE;
  129.     }
  130.     return FALSE;
  131. }
  132. //
  133. // AppCompat - Sequel NetPIM execs a browser and then waits forever
  134. // looking for a visible top level window owned by this process.
  135. //
  136. HWND CreateAppCompatWindow(HINSTANCE hinst)
  137. {
  138.     HWND hwnd;
  139.     static const TCHAR c_szClass[] = TEXT("IEDummyFrame");  // IE3 used "IEFrame"
  140.     WNDCLASS wc = { 0, DefWindowProc, 0, 0, hinst, NULL, NULL, NULL, NULL, c_szClass };
  141.     RegisterClass(&wc);
  142.     // Netmanage ECCO Pro asks to get the menu...
  143.     HMENU hmenu = CreateMenu();
  144.     hwnd = CreateWindowEx(WS_EX_TOOLWINDOW, c_szClass, TEXT(""), 0,
  145.                           0x00007FF0, 0x00007FF0, 0, 0,
  146.                           NULL, hmenu, hinst, NULL);
  147.     // Don't open SHOWDEFAULT or this turkey could end up maximized
  148.     ShowWindow(hwnd, SW_SHOWNA);
  149.     return hwnd;
  150. }
  151. #define USERAGENT_POST_PLATFORM_PATH_TO_KEY    TEXT("Software\Microsoft\Windows\CurrentVersion\Internet Settings\User Agent\Post Platform")
  152. void SetCompatModeUserAgentString(void)
  153. {
  154.     HKEY hkey;
  155.     const char szcompat[]=TEXT("compat");
  156.     
  157.     if (ERROR_SUCCESS == RegCreateKey(HKEY_CURRENT_USER, USERAGENT_POST_PLATFORM_PATH_TO_KEY, &hkey))
  158.     {
  159.         RegSetValueEx( hkey,
  160.                        szcompat,
  161.                        0,
  162.                        REG_BINARY,
  163.                        (LPBYTE)NULL, 0);
  164.         RegCloseKey(hkey);
  165.     }
  166.     
  167. }
  168. // Tell the user they are running in compat mode and not all the features will be available.
  169. #define IECOMPAT_REG_VAL    TEXT("CompatWarningFor")
  170. void WarnCompatMode(HINSTANCE hinst)
  171. {
  172.     TCHAR szFqFilename[MAX_PATH];
  173.     TCHAR szRegVal[MAX_PATH];
  174.     TCHAR szTitle[255];
  175.     TCHAR szMsg[1024];
  176.     LPTSTR szFile;
  177.     GetModuleFileName(NULL, szFqFilename, ARRAYSIZE(szFqFilename));
  178.     szFile = PathFindFileName(szFqFilename);
  179.     
  180.     // Build up string "compatmodewarningfor <exe name>" as value for reg key
  181.     lstrcpy(szRegVal, IECOMPAT_REG_VAL);
  182.     lstrcat(szRegVal, szFile);
  183.     LoadString(hinst, IDS_COMPATMODEWARNINGTITLE, szTitle, ARRAYSIZE(szTitle));
  184.     LoadString(hinst, IDS_COMPATMODEWARNING, szMsg, ARRAYSIZE(szMsg));
  185.     SHMessageBoxCheck(NULL, szMsg, szTitle, MB_OK, FALSE, szRegVal);
  186. }
  187. #ifdef WINNT
  188. // this is the same code that is in explorer.exe (initcab.c)
  189. #define RSA_PATH_TO_KEY    TEXT("Software\Microsoft\Cryptography\Defaults\Provider\Microsoft Base Cryptographic Provider v1.0")
  190. #define CSD_REG_PATH       TEXT("System\CurrentControlSet\Control\Windows")
  191. #define CSD_REG_VALUE      TEXT("CSDVersion")
  192. // the signatures we are looking for in the regsitry so that we can patch up 
  193. #ifdef _M_IX86
  194. static  BYTE  SP3Sig[] = {0xbd, 0x9f, 0x13, 0xc5, 0x92, 0x12, 0x2b, 0x72,
  195.                           0x4a, 0xba, 0xb6, 0x2a, 0xf9, 0xfc, 0x54, 0x46,
  196.                           0x6f, 0xa1, 0xb4, 0xbb, 0x43, 0xa8, 0xfe, 0xf8,
  197.                           0xa8, 0x23, 0x7d, 0xd1, 0x85, 0x84, 0x22, 0x6e,
  198.                           0xb4, 0x58, 0x00, 0x3e, 0x0b, 0x19, 0x83, 0x88,
  199.                           0x6a, 0x8d, 0x64, 0x02, 0xdf, 0x5f, 0x65, 0x7e,
  200.                           0x3b, 0x4d, 0xd4, 0x10, 0x44, 0xb9, 0x46, 0x34,
  201.                           0xf3, 0x40, 0xf4, 0xbc, 0x9f, 0x4b, 0x82, 0x1e,
  202.                           0xcc, 0xa7, 0xd0, 0x2d, 0x22, 0xd7, 0xb1, 0xf0,
  203.                           0x2e, 0xcd, 0x0e, 0x21, 0x52, 0xbc, 0x3e, 0x81,
  204.                           0xb1, 0x1a, 0x86, 0x52, 0x4d, 0x3f, 0xfb, 0xa2,
  205.                           0x9d, 0xae, 0xc6, 0x3d, 0xaa, 0x13, 0x4d, 0x18,
  206.                           0x7c, 0xd2, 0x28, 0xce, 0x72, 0xb1, 0x26, 0x3f,
  207.                           0xba, 0xf8, 0xa6, 0x4b, 0x01, 0xb9, 0xa4, 0x5c,
  208.                           0x43, 0x68, 0xd3, 0x46, 0x81, 0x00, 0x7f, 0x6a,
  209.                           0xd7, 0xd1, 0x69, 0x51, 0x47, 0x25, 0x14, 0x40,
  210.                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  211. #else // other than _M_IX86
  212. static  BYTE  SP3Sig[] = {0x8a, 0x06, 0x01, 0x6d, 0xc2, 0xb5, 0xa2, 0x66,
  213.                           0x12, 0x1b, 0x9c, 0xe4, 0x58, 0xb1, 0xf8, 0x7d,
  214.                           0xad, 0x17, 0xc1, 0xf9, 0x3f, 0x87, 0xe3, 0x9c,
  215.                           0xdd, 0xeb, 0xcc, 0xa8, 0x6b, 0x62, 0xd0, 0x72,
  216.                           0xe7, 0xf2, 0xec, 0xd6, 0xd6, 0x36, 0xab, 0x2d,
  217.                           0x28, 0xea, 0x74, 0x07, 0x0e, 0x6c, 0x6d, 0xe1,
  218.                           0xf8, 0x17, 0x97, 0x13, 0x8d, 0xb1, 0x8b, 0x0b,
  219.                           0x33, 0x97, 0xc5, 0x46, 0x66, 0x96, 0xb4, 0xf7,
  220.                           0x03, 0xc5, 0x03, 0x98, 0xf7, 0x91, 0xae, 0x9d,
  221.                           0x00, 0x1a, 0xc6, 0x86, 0x30, 0x5c, 0xc8, 0xc7,
  222.                           0x05, 0x47, 0xed, 0x2d, 0xc2, 0x0b, 0x61, 0x4b,
  223.                           0xce, 0xe5, 0xb7, 0xd7, 0x27, 0x0c, 0x9e, 0x2f,
  224.                           0xc5, 0x25, 0xe3, 0x81, 0x13, 0x9d, 0xa2, 0x67,
  225.                           0xb2, 0x26, 0xfc, 0x99, 0x9d, 0xce, 0x0e, 0xaf,
  226.                           0x30, 0xf3, 0x30, 0xec, 0xa3, 0x0a, 0xfe, 0x16,
  227.                           0xb6, 0xda, 0x16, 0x90, 0x9a, 0x9a, 0x74, 0x7a,
  228.                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  229. #endif      // _M_IX86
  230. void CheckForSP3RSAOverwrite( void )
  231. {
  232.     // check for them having installed NTSP3 over the top of IE4, it nukes
  233.     // the RSABASE reg stuff, so we have to re-do it. (our default platform is NT + SP3, but this
  234.     // problem doesn't occur on NT5, so ignore it.
  235.     OSVERSIONINFO osVer;
  236.     ZeroMemory(&osVer, sizeof(osVer));
  237.     osVer.dwOSVersionInfoSize = sizeof(osVer);
  238.     if( GetVersionEx(&osVer) && (osVer.dwPlatformId == VER_PLATFORM_WIN32_NT) 
  239.         && (osVer.dwMajorVersion == 4))
  240.     {
  241.         // now check to see we are on SP3 ...
  242.         DWORD dwValue = 0;
  243.         DWORD dwSize = sizeof( dwValue );
  244.         
  245.         if ( ERROR_SUCCESS == SHGetValue( HKEY_LOCAL_MACHINE, CSD_REG_PATH, CSD_REG_VALUE, NULL,
  246.              &dwValue, &dwSize) && LOWORD( dwValue ) == 0x300 )
  247.         {
  248.             BYTE rgbSig[136];
  249.             dwSize = sizeof(rgbSig);
  250.             
  251.             if (ERROR_SUCCESS == SHGetValue ( HKEY_LOCAL_MACHINE, RSA_PATH_TO_KEY, TEXT("Signature"), NULL,
  252.                 rgbSig, &dwSize))
  253.             {
  254.                 if ((dwSize == sizeof(SP3Sig)) && 
  255.                     (0 == memcmp(SP3Sig, rgbSig, sizeof(SP3Sig))))
  256.                 {
  257.                     // need to do a DLLRegisterServer on RSABase
  258.                     HINSTANCE hInst = LoadLibrary(TEXT("rsabase.dll"));
  259.                     if ( hInst )
  260.                     {
  261.                         FARPROC pfnDllReg = GetProcAddress( hInst, "DllRegisterServer");
  262.                         if ( pfnDllReg )
  263.                         {
  264.                             __try
  265.                             {
  266.                                 pfnDllReg();
  267.                             }
  268.                             __except( EXCEPTION_EXECUTE_HANDLER)
  269.                             {
  270.                             }
  271.                             __endexcept
  272.                         }
  273.                         FreeLibrary( hInst );
  274.                     }
  275.                 }
  276.             }
  277.         }           
  278.     }
  279. }
  280. #else
  281. #define CheckForSP3RSAOverwrite() 
  282. #endif
  283. #define TEN_SECONDS (10 * 1000)
  284. //---------------------------------------------------------------------------
  285. int WinMainT(HINSTANCE hinst, HINSTANCE hPrevInstance, LPTSTR lpszCmdLine, int nCmdShow)
  286. {
  287. #ifdef DEBUG
  288.     CcshellGetDebugFlags();
  289. #endif
  290.     int  iRet = TRUE;
  291.     HWND hwndDesktop ;
  292.     BOOL fNowait = FALSE;
  293.     BOOL fInproc = FALSE;
  294.     BOOL fEval   = FALSE;
  295. #ifdef UNIX
  296.     BOOL fRemote = FALSE;
  297. #endif
  298.     while (1) {
  299. #ifdef UNIX
  300.         if (IsCommandSwitch(lpszCmdLine, TEXT("-remote"), TRUE))
  301.         {
  302.             fRemote = TRUE;
  303.         }
  304. #endif
  305.         if (IsCommandSwitch(lpszCmdLine, TEXT("-eval"), TRUE))
  306.         {
  307.             fInproc = TRUE;
  308.             fEval   = TRUE;
  309.         } else if (IsCommandSwitch(lpszCmdLine, TEXT("-new"), TRUE))
  310.         {
  311.             fInproc = TRUE;
  312.         }
  313.         else if (IsCommandSwitch(lpszCmdLine, TEXT("-nowait"), TRUE)) 
  314.         {
  315.             fNowait = TRUE;
  316.         } 
  317.         else
  318.             break;
  319.     }
  320. #ifndef UNIX
  321.     if (!GetModuleHandle(TEXT("IEXPLORE.EXE")))
  322.     {
  323.         // For side by side install auto dection, if IExplore.exe is renamed, assume this is a side by side do dah
  324.         // and we want to run in "evaluation" mode.
  325.         fInproc = TRUE;
  326.         fEval   = TRUE;        
  327.     }
  328. #endif
  329.     
  330.     // Should we run browser in a new process?
  331.     if (fInproc || SHRegGetBoolUSValue(c_szBrowseNewProcessReg, c_szBrowseNewProcess, FALSE, FALSE))
  332.     {
  333.         goto InThisProcess;
  334.     }
  335. #ifdef UNIX
  336.     if (!(fRemote && ConnectRemoteIE(lpszCmdLine, hinst)))
  337. #endif
  338.     
  339.     if (WhichPlatform() == PLATFORM_INTEGRATED && (hwndDesktop = GetShellWindow()))
  340.     {
  341.         //
  342.         // Integrated browser mode - package up a bunch of data into a COPYDATASTRUCT,
  343.         // and send it to the desktop window via SendMessage(WM_COPYDATA).
  344.         //
  345.         COPYDATASTRUCT cds;
  346.         cds.dwData = nCmdShow;
  347.         //
  348.         // First piece of data is a wide string version of the command line params.
  349.         //
  350.         LPWSTR pwszBuffer = (LPWSTR)LocalAlloc(LPTR, (INTERNET_MAX_URL_LENGTH + 2 * MAX_IEEVENTNAME) * sizeof(WCHAR));;
  351.         if (pwszBuffer)
  352.         {
  353. #ifdef UNICODE
  354.             lstrcpy(pwszBuffer, lpszCmdLine);
  355. #else
  356.             int cch = MultiByteToWideChar(CP_ACP, 0, lpszCmdLine, -1, pwszBuffer, INTERNET_MAX_URL_LENGTH);
  357.             Assert(cch);
  358. #endif
  359.             cds.lpData = pwszBuffer;
  360.             cds.cbData = sizeof(WCHAR) * (lstrlenW((LPCWSTR)cds.lpData) + 1);
  361.             //
  362.             // Second piece of data is the event to fire when
  363.             // the browser window reaches WM_CREATE.
  364.             //
  365.             HANDLE hEventReady = AppendEvent(&cds);
  366.             if (hEventReady)
  367.             {
  368.                 //
  369.                 // Third piece of data is the event to fire when
  370.                 // the browser window closes.  This is optional,
  371.                 // we only create it (and wait for it) when there
  372.                 // are command line parameters.
  373.                 //
  374.                 HANDLE hEventDead = NULL;
  375.                 // The hard part is to figure out when we need the command line and when
  376.                 // we don't. For the most part if there is a command line we will assume that
  377.                 // we will need it (potentially) we could look for the -nowait flag.  But then
  378.                 // there are others like NetManage ECCO Pro who do their equiv of ShellExecute
  379.                 // who don't pass a command line...
  380.                 if ((*lpszCmdLine || CheckForNeedingAppCompatWindow()) && !fNowait)
  381.                 {
  382.                     hEventDead = AppendEvent(&cds);
  383.                 }
  384.                 
  385.                 if (hEventDead || !*lpszCmdLine || fNowait)
  386.                 {
  387.                     //
  388.                     // Send that message!
  389.                     //
  390.                     int iRet = (int)SendMessage(hwndDesktop, WM_COPYDATA, (WPARAM)hwndDesktop, (LPARAM)&cds);
  391.                     //
  392.                     // Nobody needs the string anymore.
  393.                     //
  394.                     LocalFree(pwszBuffer);
  395.                     pwszBuffer = NULL;
  396.                     if (iRet)
  397.                     {
  398.                         //
  399.                         // First, we wait for the browser window to hit WM_CREATE.
  400.                         // When this happens, all DDE servers will have been registered.
  401.                         //
  402.                         DWORD dwRet = WaitForSingleObject(hEventReady, TEN_SECONDS);
  403.                         ASSERT(dwRet == WAIT_OBJECT_0);
  404.                         if (hEventDead)
  405.                         {
  406.                             //
  407.                             // Create an offscreen IE-lookalike window
  408.                             // owned by this process for app compat reasons.
  409.                             //
  410.                             HWND hwnd = CreateAppCompatWindow(hinst);
  411.                             do
  412.                             {
  413.                                 //
  414.                                 // Calling MsgWait... will cause any threads blocked
  415.                                 // on WaitForInputIdle(IEXPLORE) to resume execution.
  416.                                 // This is fine because the browser has already
  417.                                 // registered its DDE servers by now.
  418.                                 //
  419.                                 dwRet = MsgWaitForMultipleObjects(1, &hEventDead, FALSE, INFINITE, QS_ALLINPUT);
  420.                                 if (dwRet == WAIT_OBJECT_0)
  421.                                 {
  422.                                     //
  423.                                     // Kill our helper window cleanly too.
  424.                                     //
  425.                                     DestroyWindow(hwnd);
  426.                                 }
  427.                                 MSG msg;
  428.                                 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  429.                                 {
  430.                                     if (msg.message == WM_QUIT)
  431.                                     {
  432.                                         //
  433.                                         // We got a quit message, drop out.
  434.                                         //
  435.                                         dwRet = WAIT_OBJECT_0;
  436.                                         break;
  437.                                     }
  438.                                     TranslateMessage(&msg);
  439.                                     DispatchMessage(&msg);
  440.                                 }
  441.                             }
  442.                             while(dwRet != WAIT_OBJECT_0);
  443.                         }
  444.                     }
  445.                     iRet = !iRet;
  446.                 }
  447.                 if (hEventDead)
  448.                 {
  449.                     CloseHandle(hEventDead);
  450.                 }
  451.                 CloseHandle(hEventReady);
  452.             }
  453.         }
  454.         if (pwszBuffer)
  455.         {
  456.             LocalFree(pwszBuffer);
  457.             pwszBuffer = NULL;
  458.         }
  459.     }        
  460.     else
  461.     {
  462. InThisProcess:
  463.         // Browser only mode, check the SP3 bug
  464.         CheckForSP3RSAOverwrite();
  465.         if (fEval)
  466.         {
  467.             // Set "compat" mode user agent
  468.             WarnCompatMode(hinst);
  469.             // #75454... let the compat mode setup set useragent in HKLM.
  470.             //SetCompatModeUserAgentString();
  471.             
  472.             // Run in eval mode. So we want everything from this dir.
  473.             LoadLibrary("comctl32.DLL");
  474.             LoadLibrary("browseui.DLL");            
  475.             LoadLibrary("shdocvw.DLL");
  476.             LoadLibrary("wininet.dll");
  477.             LoadLibrary("urlmon.dll");
  478.             LoadLibrary("mlang.dll");
  479.             LoadLibrary("mshtml.dll");
  480.             LoadLibrary("jscript.DLL");            
  481.         }
  482.         
  483.         iRet = IEWinMain(lpszCmdLine, nCmdShow);
  484.     }
  485.     return iRet;
  486. }
  487. // DllGetLCID
  488. //
  489. // this API is for Office to retrieve our UI language
  490. // when they are hosted by iexplore.
  491. //
  492. STDAPI_(LCID) DllGetLCID (IBindCtx * pbc)
  493. {
  494.      return MLGetUILanguage();
  495. }