// -------------------------------------------------------------------------------- // MSIMN.C // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved // -------------------------------------------------------------------------------- #include "pch.h" #define DEFINE_STRCONST #include #include "msimnp.h" #include "res.h" #include "../msoeres/resource.h" #include "shared.h" #include "msoert.h" #include "shlwapi.h" #include "shlwapip.h" #include #include "error.h" // -------------------------------------------------------------------------------- // String Consts // -------------------------------------------------------------------------------- static const WCHAR c_wszRegCmd[] = L"/reg"; static const WCHAR c_wszUnRegCmd[] = L"/unreg"; static const WCHAR c_wszEmpty[] = L""; static const char c_szLangDll[] = "MSOERES.DLL"; static const char c_szOLNewsKey[] = "Software\\Clients\\News\\Microsoft Outlook"; static const char c_szRegOLNews[] = "OLNews"; static const char c_szRegFlat[] = "Software\\Microsoft\\Outlook Express"; static const char c_szDontUpgradeOLNews[] = "NoUpgradeOLNews"; // -------------------------------------------------------------------------------- // Debug Strings // -------------------------------------------------------------------------------- #ifdef DEBUG static const TCHAR c_szDebug[] = "mshtmdbg.dll"; static const TCHAR c_szDebugUI[] = "DbgExDoTracePointsDialog"; static const TCHAR c_szRegSpy[] = "DbgExGetMallocSpy"; static const WCHAR c_wszInvokeUI[] = L"/d"; #endif // -------------------------------------------------------------------------------- // MSHTMDBG.DLL Prototypes // -------------------------------------------------------------------------------- #ifdef DEBUG typedef void (STDAPICALLTYPE *PFNDEBUGUI)(BOOL); typedef void *(STDAPICALLTYPE *PFNREGSPY)(void); #endif // -------------------------------------------------------------------------------- // Debug Prototypes // -------------------------------------------------------------------------------- #ifdef DEBUG void LoadMSHTMDBG(LPWSTR pwszCmdLine); #endif // -------------------------------------------------------------------------------- // Prototypes // -------------------------------------------------------------------------------- int WinMainT(HINSTANCE hInst, HINSTANCE hInstPrev, LPWSTR pwszCmdLine, int nCmdShow); // -------------------------------------------------------------------------------- // UpgradeOLNewsReader() // -------------------------------------------------------------------------------- void UpgradeOLNewsReader(HINSTANCE hInst) { HKEY hkey; BOOL fOK = TRUE; DWORD dwDont, cb; // Make sure this functionality hasn't been disabled if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szRegFlat, 0, KEY_READ, &hkey)) { cb = sizeof(dwDont); if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szDontUpgradeOLNews, 0, NULL, (LPBYTE)&dwDont, &cb)) fOK = 0 == dwDont; RegCloseKey(hkey); } if (fOK && ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szOLNewsKey, 0, KEY_READ, &hkey)) { RegCloseKey(hkey); CallRegInstall(hInst, hInst, c_szRegOLNews, (LPSTR)c_szOLNewsKey); } } // -------------------------------------------------------------------------------- // ModuleEntry - Stolen from the CRT, used to shirink our code // -------------------------------------------------------------------------------- int _stdcall ModuleEntry(void) { // Locals int i; STARTUPINFOA si; LPWSTR pwszCmdLine; // Get the command line pwszCmdLine = GetCommandLineW(); // We don't want the "No disk in drive X:" requesters, so we set the critical error mask such that calls will just silently fail SetErrorMode(SEM_FAILCRITICALERRORS); // Parse the command line if ( *pwszCmdLine == L'\"') { // Scan, and skip over, subsequent characters until another double-quote or a null is encountered. while ( *++pwszCmdLine && (*pwszCmdLine != L'\"')) {}; // If we stopped on a double-quote (usual case), skip over it. if (*pwszCmdLine == L'\"') pwszCmdLine++; } else { while (*pwszCmdLine > L' ') pwszCmdLine++; } // Skip past any white space preceeding the second token. while (*pwszCmdLine && (*pwszCmdLine <= L' ')) pwszCmdLine++; // Get startup information... si.dwFlags = 0; GetStartupInfoA(&si); // Call the real winmain i = WinMainT(GetModuleHandle(NULL), NULL, pwszCmdLine, (si.dwFlags & STARTF_USESHOWWINDOW) ? si.wShowWindow : SW_SHOWDEFAULT); // Since we now have a way for an extension to tell us when it is finished, we will terminate all processes when the main thread goes away. ExitProcess(i); // Done return i; } // -------------------------------------------------------------------------------- // WinMain // -------------------------------------------------------------------------------- int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR pszCmdLine, int nCmdShow) { // Just call ModuleEntry return(ModuleEntry()); } // -------------------------------------------------------------------------------- // WinMainT // -------------------------------------------------------------------------------- int WinMainT(HINSTANCE hInst, HINSTANCE hInstPrev, LPWSTR pwszCmdLine, int nCmdShow) { // Locals HANDLE hMutex=NULL; HWND hwnd; DWORD dwWait, dwError; INT nErrorIds=0; PFNSTART pfnStart; HINSTANCE hInstMSOEDLL=NULL; HRESULT hrOE; HINSTANCE hInstUSER=NULL; static BOOL fFirstID=TRUE; // Register if (0 == StrCmpIW(c_wszRegCmd, pwszCmdLine)) { CallRegInstall(hInst, hInst, c_szReg, NULL); // It not great to do this here, but we've only just written the OEOL keys, // and it would be worst to hit the reg during startup UpgradeOLNewsReader(hInst); return(1); } // Unregister else if (0 == StrCmpIW(c_wszUnRegCmd, pwszCmdLine)) { CallRegInstall(hInst, hInst, c_szUnReg, NULL); return(1); } // Create the start shared mutex hMutex = CreateMutex(NULL, FALSE, STR_MSOEAPI_INSTANCEMUTEX); if (NULL == hMutex) { nErrorIds = idsStartupCantCreateMutex; goto exit; } // Wait for any current startups/shutdowns to finish dwWait = WaitForSingleObject(hMutex, (1000 * 60)); if (dwWait != WAIT_OBJECT_0) { nErrorIds = idsStartupCantWaitForMutex; goto exit; } // Look for a current instance of the application hwnd = FindWindowWrapW(STRW_MSOEAPI_INSTANCECLASS, NULL); // is there another instance running already? if (NULL != hwnd) { // Locals COPYDATASTRUCT cds; DWORD_PTR dwResult; // Some friendly output IF_DEBUG(OutputDebugString("Another instance of Athena was found...\n\n");) // Initialize the Copy data structure cds.dwData = MSOEAPI_ACDM_CMDLINE; cds.cbData = pwszCmdLine ? (lstrlenW(pwszCmdLine)+1)*sizeof(*pwszCmdLine) : 0; cds.lpData = pwszCmdLine; // On NT5, we need to call this to allow our window in the other process to take the foreground hInstUSER = LoadLibrary("USER32.DLL"); if (hInstUSER) { FARPROC pfn = GetProcAddress(hInstUSER, "AllowSetForegroundWindow"); if (pfn) { DWORD dwProcessId; GetWindowThreadProcessId(hwnd, &dwProcessId); (*pfn)(dwProcessId); } FreeLibrary(hInstUSER); } // Show the window into the foreground SetForegroundWindow(hwnd); SendMessageTimeout(hwnd, WM_COPYDATA, (WPARAM)NULL, (LPARAM)&cds, SMTO_ABORTIFHUNG, 1500, &dwResult); } // Lets load msoe.dll else { // Load Debug DLL IF_DEBUG(LoadMSHTMDBG(pwszCmdLine);) // Get the proc address of MSOE.DLL hInstMSOEDLL = LoadLibrary(STR_MSOEAPI_DLLNAME); // Did we load the dll if (NULL == hInstMSOEDLL) { dwError = GetLastError(); if (dwError == ERROR_MOD_NOT_FOUND) { if (0xffffffff == GetFileAttributes(STR_MSOEAPI_DLLNAME)) nErrorIds = idsStartupCantFindMSOEDLL; else nErrorIds = idsStartupModNotFoundMSOEDLL; } else if (dwError == ERROR_DLL_INIT_FAILED) { if (0xffffffff == GetFileAttributes(c_szLangDll)) nErrorIds = idsStartupCantFindResMSOEDLL; else nErrorIds = idsStartupDllInitFailedMSOEDLL; } else { nErrorIds = idsStartupCantLoadMSOEDLL; } goto exit; } // Unlikely that this will fail pfnStart = (PFNSTART)GetProcAddress(hInstMSOEDLL, STR_MSOEAPI_START); // Did that Fail if (NULL == pfnStart) { nErrorIds = idsStartupCantLoadMSOEDLL; goto exit; } hrOE = S_RESTART_OE; while (S_RESTART_OE == hrOE) { hrOE = pfnStart(MSOEAPI_START_APPLICATION, (fFirstID ? pwszCmdLine : c_wszEmpty), nCmdShow); fFirstID = FALSE; } // NB: pfnInit will not return until the main message pump terminates if (SUCCEEDED(hrOE)) { CloseHandle(hMutex); hMutex = NULL; } // The dll couldn't be loaded, as long as it wasn't due to need for ICW, display error else if (hrOE != hrUserCancel && hrOE != MAPI_E_USER_CANCEL) { nErrorIds = idsStartupCantInitMSOEDLL; goto exit; } } exit: // Cleanup if (hMutex) { ReleaseMutex(hMutex); CloseHandle(hMutex); } // Free msoe.dll if (hInstMSOEDLL) FreeLibrary(hInstMSOEDLL); // Show an error ? if (0 != nErrorIds) { // Locals CHAR szRes[255]; CHAR szTitle[100]; // Load the LoadString(hInst, idsOutlookExpress, szTitle, ARRAYSIZE(szTitle)); // Load the LoadString(hInst, nErrorIds, szRes, ARRAYSIZE(szRes)); // Show the error message MessageBox(NULL, szRes, szTitle, MB_OK | MB_SETFOREGROUND | MB_ICONEXCLAMATION); } IF_DEBUG(CoRevokeMallocSpy()); // Done return nErrorIds; } #ifdef DEBUG // -------------------------------------------------------------------------------- // LoadMSHTMDBG // -------------------------------------------------------------------------------- void LoadMSHTMDBG(LPWSTR pwszCmdLine) { // Load mshtmdbg.dll HINSTANCE hInstDebug = LoadLibrary(c_szDebug); // Did it load ? if (NULL != hInstDebug) { // Locals PFNREGSPY pfnRegSpy; // If the user passed /d on the command line, lets configure mshtmdbg.dll if (0 == StrCmpIW(pwszCmdLine, c_wszInvokeUI)) { // Locals PFNDEBUGUI pfnDebugUI; // Get the proc address of the UI pfnDebugUI = (PFNDEBUGUI)GetProcAddress(hInstDebug, c_szDebugUI); if (NULL != pfnDebugUI) { (*pfnDebugUI)(TRUE); goto exit; } } // Get the process address of the registration pfnRegSpy = (PFNREGSPY)GetProcAddress(hInstDebug, c_szRegSpy); if (NULL != pfnRegSpy) { LPMALLOCSPY pSpy = (IMallocSpy *)(*pfnRegSpy)(); SideAssert(SUCCEEDED(CoRegisterMallocSpy(pSpy))); } } exit: // Done return; } #endif // DEBUG