Back to index

lightning-sunbird  0.9+nobinonly
control_kicker.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is the Mozilla browser.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications, Inc.
00020  * Portions created by the Initial Developer are Copyright (C) 1999
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Adam Lock <adamlock@netscape.com>
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include "stdafx.h"
00041 
00042 #include <sys/types.h>
00043 #include <sys/stat.h>
00044 
00045 #include "shlobj.h"
00046 
00047 static BOOL LoadMozLibraryFromCurrentDir();
00048 static BOOL LoadMozLibraryFromRegistry(BOOL bAskUserToSetPath);
00049 static BOOL LoadLibraryWithPATHFixup(const TCHAR *szBinDirPath);
00050 
00051 
00052 static HMODULE ghMozCtlX = NULL;
00053 static HMODULE ghMozCtl = NULL;
00054 
00055 static LPCTSTR c_szMozCtlDll = _T("mozctl.dll");
00056 static LPCTSTR c_szMozillaControlKey = _T("Software\\Mozilla\\");
00057 static LPCTSTR c_szMozillaBinDirPathValue = _T("BinDirectoryPath");
00058 static LPCTSTR c_szMozCtlInProcServerKey =
00059     _T("CLSID\\{1339B54C-3453-11D2-93B9-000000000000}\\InProcServer32");
00060 
00061 // Message strings - should come from a resource file
00062 static LPCTSTR c_szWarningTitle =
00063     _T("Mozilla Control Warning");
00064 static LPCTSTR c_szErrorTitle =
00065     _T("Mozilla Control Error");
00066 static LPCTSTR c_szPrePickFolderMsg =
00067     _T("The Mozilla control was unable to detect where your Mozilla "
00068        "layout libraries may be found. You will now be shown a directory "
00069        "picker for you to locate them.");
00070 static LPCTSTR c_szPickFolderDlgTitle =
00071     _T("Pick where the Mozilla bin directory is located, "
00072        "e.g. (c:\\mozilla\\bin)");
00073 static LPCTSTR c_szRegistryErrorMsg =
00074     _T("The Mozilla control was unable to store the location of the Mozilla"
00075        "layout libraries in the registry. This may be due to the host "
00076        "program running with insufficient permissions to write there.\n\n"
00077        "You should consider running the control once as Administrator "
00078        "to enable this entry to added or alternatively move the "
00079        "control files mozctlx.dll and mozctl.dll into the same folder as "
00080        "the other libraries.");
00081 static LPCTSTR c_szLoadErrorMsg =
00082     _T("The Mozilla control could not be loaded correctly. This is could "
00083        "be due to an invalid location being specified for the Mozilla "
00084        "layout libraries or missing files from your installation.\n\n"
00085        "Visit http://www.iol.ie/~locka/mozilla/mozilla.htm for in-depth"
00086        "troubleshooting advice.");
00087 
00088 BOOL APIENTRY DllMain( HANDLE hModule, 
00089                        DWORD  ul_reason_for_call, 
00090                        LPVOID lpReserved
00091                      )
00092 {
00093     switch (ul_reason_for_call)
00094     {
00095     case DLL_PROCESS_ATTACH:
00096         ghMozCtlX = (HMODULE) hModule;
00097         break;
00098     case DLL_THREAD_ATTACH:
00099         break;
00100     case DLL_THREAD_DETACH:
00101         break;
00102     case DLL_PROCESS_DETACH:
00103         if (ghMozCtl)
00104         {
00105             FreeLibrary(ghMozCtl);
00106             ghMozCtl = NULL;
00107         }
00108         break;
00109     }
00110     return TRUE;
00111 }
00112 
00113 static BOOL LoadMozLibrary(BOOL bAskUserToSetPath = TRUE)
00114 {
00115     if (ghMozCtl)
00116     {
00117         return TRUE;
00118     }
00119 
00120     ghMozCtl = LoadLibrary(c_szMozCtlDll);
00121     if (ghMozCtl)
00122     {
00123         return TRUE;
00124     }
00125 
00126     if (LoadMozLibraryFromCurrentDir())
00127     {
00128         return TRUE;
00129     }
00130 
00131     if (LoadMozLibraryFromRegistry(bAskUserToSetPath))
00132     {
00133         return TRUE;
00134     }
00135 
00136     ::MessageBox(NULL, c_szLoadErrorMsg, c_szErrorTitle, MB_OK);
00137 
00138     return FALSE;
00139 }
00140 
00141 static BOOL LoadMozLibraryFromCurrentDir()
00142 {
00143     TCHAR szMozCtlXPath[MAX_PATH + 1];
00144 
00145     // Get this module's path
00146     ZeroMemory(szMozCtlXPath, sizeof(szMozCtlXPath));
00147     GetModuleFileName(ghMozCtlX, szMozCtlXPath,
00148         sizeof(szMozCtlXPath) / sizeof(szMozCtlXPath[0]));
00149 
00150     // Make the control path
00151     TCHAR szTmpDrive[_MAX_DRIVE];
00152     TCHAR szTmpDir[_MAX_DIR];
00153     TCHAR szTmpFname[_MAX_FNAME];
00154     TCHAR szTmpExt[_MAX_EXT];
00155     _tsplitpath(szMozCtlXPath, szTmpDrive, szTmpDir, szTmpFname, szTmpExt);
00156 
00157     TCHAR szMozCtlPath[MAX_PATH + 1];
00158     ZeroMemory(szMozCtlPath, sizeof(szMozCtlPath));
00159     _tmakepath(szMozCtlPath, szTmpDrive, szTmpDir, c_szMozCtlDll, NULL);
00160 
00161     // Stat to see if the control exists
00162     struct _stat dirStat;
00163     if (_tstat(szMozCtlPath, &dirStat) == 0)
00164     {
00165         TCHAR szBinDirPath[MAX_PATH + 1];
00166         ZeroMemory(szBinDirPath, sizeof(szBinDirPath));
00167         _tmakepath(szBinDirPath, szTmpDrive, szTmpDir, NULL, NULL);
00168         if (LoadLibraryWithPATHFixup(szBinDirPath))
00169         {
00170             return TRUE;
00171         }
00172     }
00173 
00174     return FALSE;
00175 }
00176 
00177 static BOOL LoadMozLibraryFromRegistry(BOOL bAskUserToSetPath)
00178 {
00179     // 
00180     HKEY hkey = NULL;
00181     
00182     TCHAR szBinDirPath[MAX_PATH + 1];
00183     DWORD dwBufSize = sizeof(szBinDirPath);
00184 
00185     ZeroMemory(szBinDirPath, dwBufSize);
00186 
00187     // First try and read the path from the registry
00188     RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szMozillaControlKey, 0, KEY_READ, &hkey);
00189     if (hkey)
00190     {
00191         DWORD dwType = REG_SZ;
00192         RegQueryValueEx(hkey, c_szMozillaBinDirPathValue, NULL, &dwType,
00193             (LPBYTE) szBinDirPath, &dwBufSize);
00194         RegCloseKey(hkey);
00195         hkey = NULL;
00196 
00197         if (lstrlen(szBinDirPath) > 0 && LoadLibraryWithPATHFixup(szBinDirPath))
00198         {
00199             return TRUE;
00200         }
00201 
00202         // NOTE: We will drop through here if the registry key existed
00203         //       but didn't lead to the control being loaded.
00204     }
00205     
00206     // Ask the user to pick to pick the path?
00207     if (bAskUserToSetPath)
00208     {
00209         // Tell the user that they have to pick the bin dir path
00210         ::MessageBox(NULL, c_szPrePickFolderMsg, c_szWarningTitle, MB_OK);
00211 
00212         // Show a folder picker for the user to choose the bin directory
00213         BROWSEINFO bi;
00214         ZeroMemory(&bi, sizeof(bi));
00215         bi.hwndOwner = NULL;
00216         bi.pidlRoot = NULL;
00217         bi.pszDisplayName = szBinDirPath;
00218         bi.lpszTitle = c_szPickFolderDlgTitle;
00219         LPITEMIDLIST pItemList = SHBrowseForFolder(&bi);
00220         if (pItemList)
00221         {
00222             // Get the path from the user selection
00223             IMalloc *pShellAllocator = NULL;
00224             SHGetMalloc(&pShellAllocator);
00225             if (pShellAllocator)
00226             {
00227                 char szPath[MAX_PATH + 1];
00228 
00229                 if (SHGetPathFromIDList(pItemList, szPath))
00230                 {
00231                     // Chop off the end path separator
00232                     int nPathSize = strlen(szPath);
00233                     if (nPathSize > 0)
00234                     {
00235                         if (szPath[nPathSize - 1] == '\\')
00236                         {
00237                             szPath[nPathSize - 1] = '\0';
00238                         }
00239                     }
00240 
00241                     // Form the file pattern
00242 #ifdef UNICODE
00243                     MultiByteToWideChar(CP_ACP, 0, szPath, szBinDirPath, -1,
00244                         sizeof(szBinDirPath) / sizeof(TCHAR));
00245 #else
00246                     lstrcpy(szBinDirPath, szPath);
00247 #endif
00248                 }
00249                 pShellAllocator->Free(pItemList);
00250                 pShellAllocator->Release();
00251             }
00252         }
00253         
00254         // Store the new path if we can
00255         if (lstrlen(szBinDirPath) > 0)
00256         {
00257             RegCreateKeyEx(HKEY_LOCAL_MACHINE, c_szMozillaControlKey, 0, NULL,
00258                 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL);
00259             if (hkey)
00260             {
00261                 RegSetValueEx(hkey, c_szMozillaBinDirPathValue, 0, REG_SZ,
00262                     (LPBYTE) szBinDirPath, lstrlen(szBinDirPath) * sizeof(TCHAR));
00263                 RegCloseKey(hkey);
00264             }
00265             else
00266             {
00267                 // Tell the user the key can't be stored but the path they 
00268                 // chose will be used for this session
00269                 ::MessageBox(NULL, c_szRegistryErrorMsg, c_szErrorTitle, MB_OK);
00270             }
00271         }
00272     }
00273 
00274     if (lstrlen(szBinDirPath) > 0 && LoadLibraryWithPATHFixup(szBinDirPath))
00275     {
00276         return TRUE;
00277     }
00278 
00279     return FALSE;
00280 }
00281 
00282 static BOOL LoadLibraryWithPATHFixup(const TCHAR *szBinDirPath)
00283 {
00284     TCHAR szOldPath[8192];
00285     TCHAR szNewPath[8192];
00286     
00287     ZeroMemory(szOldPath, sizeof(szOldPath));
00288     ZeroMemory(szNewPath, sizeof(szNewPath));
00289 
00290     // Append path to front of PATH
00291     GetEnvironmentVariable("PATH", szOldPath, sizeof(szOldPath) / sizeof(TCHAR));
00292     lstrcat(szNewPath, szBinDirPath);
00293     lstrcat(szNewPath, _T(";"));
00294     lstrcat(szNewPath, szOldPath);
00295     SetEnvironmentVariable("PATH", szNewPath);
00296     
00297     // Attempt load
00298     ghMozCtl = LoadLibrary(c_szMozCtlDll);
00299     if (ghMozCtl)
00300     {
00301         return TRUE;
00302     }
00303 
00304     // Restore old PATH
00305     SetEnvironmentVariable("PATH", szOldPath);
00306 
00307     return FALSE;
00308 }
00309 
00310 
00311 static BOOL FixupInProcRegistryEntry()
00312 {
00313     TCHAR szMozCtlXLongPath[MAX_PATH+1];
00314     ZeroMemory(szMozCtlXLongPath, sizeof(szMozCtlXLongPath));
00315     GetModuleFileName(ghMozCtlX, szMozCtlXLongPath,
00316         sizeof(szMozCtlXLongPath) * sizeof(TCHAR));
00317 
00318     TCHAR szMozCtlXPath[MAX_PATH+1];
00319     ZeroMemory(szMozCtlXPath, sizeof(szMozCtlXPath));
00320     GetShortPathName(szMozCtlXLongPath, szMozCtlXPath,
00321         sizeof(szMozCtlXPath) * sizeof(TCHAR));
00322 
00323     HKEY hkey = NULL;
00324     RegOpenKeyEx(HKEY_CLASSES_ROOT, c_szMozCtlInProcServerKey, 0, KEY_ALL_ACCESS, &hkey);
00325     if (hkey)
00326     {
00327         RegSetValueEx(hkey, NULL, 0, REG_SZ, (LPBYTE) szMozCtlXPath,
00328             lstrlen(szMozCtlXPath) * sizeof(TCHAR));
00329         RegCloseKey(hkey);
00330         return TRUE;
00331     }
00332 
00333     return FALSE;
00334 }
00335 
00337 // Used to determine whether the DLL can be unloaded by OLE
00338 
00339 typedef HRESULT (STDAPICALLTYPE *DllCanUnloadNowFn)(void);
00340 
00341 STDAPI DllCanUnloadNow(void)
00342 {
00343     if (LoadMozLibrary())
00344     {
00345         DllCanUnloadNowFn pfn = (DllCanUnloadNowFn)
00346             GetProcAddress(ghMozCtl, _T("DllCanUnloadNow"));
00347         if (pfn)
00348         {
00349             return pfn();
00350         }
00351     }
00352     return S_OK;
00353 }
00354 
00356 // Returns a class factory to create an object of the requested type
00357 
00358 typedef HRESULT (STDAPICALLTYPE *DllGetClassObjectFn)(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
00359 
00360 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
00361 {
00362     if (LoadMozLibrary())
00363     {
00364         DllGetClassObjectFn pfn = (DllGetClassObjectFn) 
00365             GetProcAddress(ghMozCtl, _T("DllGetClassObject"));
00366         if (pfn)
00367         {
00368             return pfn(rclsid, riid, ppv);
00369         }
00370     }
00371     return E_FAIL;
00372 }
00373 
00375 // DllRegisterServer - Adds entries to the system registry
00376 
00377 typedef HRESULT (STDAPICALLTYPE *DllRegisterServerFn)(void);
00378 
00379 STDAPI DllRegisterServer(void)
00380 {
00381     if (LoadMozLibrary())
00382     {
00383         DllRegisterServerFn pfn = (DllRegisterServerFn) 
00384             GetProcAddress(ghMozCtl, _T("DllRegisterServer"));
00385         if (pfn)
00386         {
00387             HRESULT hr = pfn();
00388             if (SUCCEEDED(hr))
00389             {
00390                 FixupInProcRegistryEntry();
00391             }
00392             return hr;
00393         }
00394     }
00395     return E_FAIL;
00396 }
00397 
00399 // DllUnregisterServer - Removes entries from the system registry
00400 
00401 typedef HRESULT (STDAPICALLTYPE *DllUnregisterServerFn)(void);
00402 
00403 STDAPI DllUnregisterServer(void)
00404 {
00405     if (LoadMozLibrary())
00406     {
00407         DllUnregisterServerFn pfn = (DllUnregisterServerFn)
00408             GetProcAddress(ghMozCtl, _T("DllUnregisterServer"));
00409         if (pfn)
00410         {
00411             return pfn();
00412         }
00413     }
00414     return E_FAIL;
00415 }