Back to index

lightning-sunbird  0.9+nobinonly
nsPluginHostCtrl.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 #include "stdafx.h"
00037 
00038 #include "Pluginhostctrl.h"
00039 #include "nsPluginHostCtrl.h"
00040 #include "nsURLDataCallback.h"
00041 #include "npn.h"
00042 
00043 #define NS_4XPLUGIN_CALLBACK(_type, _name) _type (__stdcall * _name)
00044 
00045 typedef NS_4XPLUGIN_CALLBACK(NPError, NP_GETENTRYPOINTS) (NPPluginFuncs* pCallbacks);
00046 typedef NS_4XPLUGIN_CALLBACK(NPError, NP_PLUGININIT) (const NPNetscapeFuncs* pCallbacks);
00047 typedef NS_4XPLUGIN_CALLBACK(NPError, NP_PLUGINSHUTDOWN) (void);
00048 
00049 const kArraySizeIncrement = 10;
00050 
00051 nsSimpleArray<nsPluginHostCtrl::LoadedPluginInfo *> nsPluginHostCtrl::m_LoadedPlugins;
00052 
00054 // nsPluginHostCtrl
00055 
00056 nsPluginHostCtrl::nsPluginHostCtrl()
00057 {
00058        m_bWindowOnly = TRUE;
00059 
00060     m_bPluginIsAlive = FALSE;
00061     m_bCreatePluginFromStreamData = FALSE;
00062     m_pLoadedPlugin = NULL;
00063 
00064     m_nArgs = 0;
00065     m_nArgsMax = 0;
00066     m_pszArgNames = NULL;
00067     m_pszArgValues = NULL;
00068 
00069     InitPluginCallbacks();
00070     memset(&m_NPPFuncs, 0, sizeof(m_NPPFuncs));
00071 }
00072 
00073 nsPluginHostCtrl::~nsPluginHostCtrl()
00074 {
00075 }
00076 
00077 LRESULT nsPluginHostCtrl::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
00078 {
00079     SetWindowLong(GWL_STYLE, GetWindowLong(GWL_STYLE) | WS_CLIPCHILDREN);
00080 
00081     // Load a list of plugins
00082     CreatePluginList(
00083         PLUGINS_FROM_IE | PLUGINS_FROM_NS4X |
00084         PLUGINS_FROM_NS6X | PLUGINS_FROM_MOZILLA);
00085 
00086     HRESULT hr = E_FAIL;
00087     if (m_bstrContentType.Length() == 0 &&
00088         m_bstrSource.Length() != 0)
00089     {
00090         USES_CONVERSION;
00091         // Do a late instantiation of the plugin based on the content type of
00092         // the stream data.
00093         m_bCreatePluginFromStreamData = TRUE;
00094         hr = OpenURLStream(OLE2T(m_bstrSource), NULL, NULL, 0);
00095     }
00096     else
00097     {
00098         // Create a plugin based upon the specified content type property
00099         USES_CONVERSION;
00100         hr = LoadPluginByContentType(OLE2T(m_bstrContentType));
00101         if (SUCCEEDED(hr))
00102         {
00103             hr = CreatePluginInstance();
00104             if (m_bstrSource.Length())
00105             {
00106                 OpenURLStream(OLE2T(m_bstrSource), NULL, NULL, 0);
00107             }
00108         }
00109     }
00110 
00111        return SUCCEEDED(hr) ? 0 : -1;
00112 }
00113 
00114 LRESULT nsPluginHostCtrl::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
00115 {
00116     DestroyPluginInstance();
00117     UnloadPlugin();
00118     CleanupPluginList();
00119     return 0;
00120 }
00121 
00122 LRESULT nsPluginHostCtrl::OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
00123 {
00124     SizeToFitPluginInstance();
00125     return 0;
00126 }
00127 
00128 LRESULT nsPluginHostCtrl::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
00129 {
00130     PAINTSTRUCT ps;
00131     HDC hdc;
00132     RECT rc;
00133 
00134     hdc = BeginPaint(&ps);
00135     GetClientRect(&rc);
00136     FillRect(hdc, &rc, (HBRUSH) GetStockObject(GRAY_BRUSH));
00137     EndPaint(&ps);
00138 
00139     return 0;
00140 }
00141 
00142 NPNetscapeFuncs nsPluginHostCtrl::g_NPNFuncs;
00143 
00144 HRESULT nsPluginHostCtrl::InitPluginCallbacks()
00145 {
00146     static BOOL gCallbacksSet = FALSE;
00147     if (gCallbacksSet)
00148     {
00149         return S_OK;
00150     }
00151 
00152     gCallbacksSet = TRUE;
00153 
00154     memset(&g_NPNFuncs, 0, sizeof(g_NPNFuncs));
00155     g_NPNFuncs.size             = sizeof(g_NPNFuncs);
00156     g_NPNFuncs.version          = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
00157     g_NPNFuncs.geturl           = NewNPN_GetURLProc(NPN_GetURL);
00158     g_NPNFuncs.posturl          = NewNPN_PostURLProc(NPN_PostURL);
00159     g_NPNFuncs.requestread      = NewNPN_RequestReadProc(NPN_RequestRead);
00160     g_NPNFuncs.newstream        = NewNPN_NewStreamProc(NPN_NewStream);
00161     g_NPNFuncs.write            = NewNPN_WriteProc(NPN_Write);
00162     g_NPNFuncs.destroystream    = NewNPN_DestroyStreamProc(NPN_DestroyStream);
00163     g_NPNFuncs.status           = NewNPN_StatusProc(NPN_Status);
00164     g_NPNFuncs.uagent           = NewNPN_UserAgentProc(NPN_UserAgent);
00165     g_NPNFuncs.memalloc         = NewNPN_MemAllocProc(NPN_MemAlloc);
00166     g_NPNFuncs.memfree          = NewNPN_MemFreeProc(NPN_MemFree);
00167     g_NPNFuncs.memflush         = NewNPN_MemFlushProc(NPN_MemFlush);
00168     g_NPNFuncs.reloadplugins    = NewNPN_ReloadPluginsProc(NPN_ReloadPlugins);
00169     g_NPNFuncs.getJavaEnv       = NewNPN_GetJavaEnvProc(NPN_GetJavaEnv);
00170     g_NPNFuncs.getJavaPeer      = NewNPN_GetJavaPeerProc(NPN_GetJavaPeer);
00171     g_NPNFuncs.geturlnotify     = NewNPN_GetURLNotifyProc(NPN_GetURLNotify);
00172     g_NPNFuncs.posturlnotify    = NewNPN_PostURLNotifyProc(NPN_PostURLNotify);
00173     g_NPNFuncs.getvalue         = NewNPN_GetValueProc(NPN_GetValue);
00174     g_NPNFuncs.setvalue         = NewNPN_SetValueProc(NPN_SetValue);
00175     g_NPNFuncs.invalidaterect   = NewNPN_InvalidateRectProc(NPN_InvalidateRect);
00176     g_NPNFuncs.invalidateregion = NewNPN_InvalidateRegionProc(NPN_InvalidateRegion);
00177     g_NPNFuncs.forceredraw      = NewNPN_ForceRedrawProc(NPN_ForceRedraw);
00178 
00179     return S_OK;
00180 }
00181 
00182 HRESULT nsPluginHostCtrl::GetWebBrowserApp(IWebBrowserApp **pBrowser)
00183 {
00184     ATLASSERT(pBrowser);
00185     if (!pBrowser)
00186     {
00187         return E_INVALIDARG;
00188     }
00189 
00190     // Get the web browser through the site the control is attached to.
00191     // Note: The control could be running in some other container than IE
00192     //       so code shouldn't expect this function to work all the time.
00193 
00194     CComPtr<IWebBrowserApp> cpWebBrowser;
00195     CComQIPtr<IServiceProvider, &IID_IServiceProvider> cpServiceProvider = m_spClientSite;
00196 
00197     HRESULT hr;
00198     if (cpServiceProvider)
00199     {
00200         hr = cpServiceProvider->QueryService(IID_IWebBrowserApp, &cpWebBrowser);
00201     }
00202     if (!cpWebBrowser)
00203     {
00204         return E_FAIL;
00205     }
00206 
00207     *pBrowser = cpWebBrowser;
00208     (*pBrowser)->AddRef();
00209 
00210     return S_OK;
00211 }
00212 
00213 HRESULT nsPluginHostCtrl::GetBaseURL(TCHAR **ppszBaseURL)
00214 {
00215     ATLASSERT(ppszBaseURL);
00216     *ppszBaseURL = NULL;
00217 
00218     CComPtr<IWebBrowserApp> cpWebBrowser;
00219     GetWebBrowserApp(&cpWebBrowser);
00220     if (!cpWebBrowser)
00221     {
00222         return E_FAIL;
00223     }
00224 
00225     USES_CONVERSION;
00226     CComBSTR bstrURL;
00227     cpWebBrowser->get_LocationURL(&bstrURL);
00228     
00229     DWORD cbBaseURL = (bstrURL.Length() + 1) * sizeof(WCHAR);
00230     DWORD cbBaseURLUsed = 0;
00231     WCHAR *pszBaseURL = (WCHAR *) malloc(cbBaseURL);
00232     ATLASSERT(pszBaseURL);
00233 
00234     CoInternetParseUrl(
00235         bstrURL.m_str,
00236         PARSE_ROOTDOCUMENT,
00237         0,
00238         pszBaseURL,
00239         cbBaseURL,
00240         &cbBaseURLUsed,
00241         0);
00242 
00243     *ppszBaseURL = _tcsdup(W2T(pszBaseURL));
00244     free(pszBaseURL);
00245 
00246     return S_OK;
00247 }
00248 
00249 HRESULT nsPluginHostCtrl::LoadPluginByContentType(const TCHAR *pszContentType)
00250 {
00251     TCHAR * pszPluginPath = NULL;
00252 
00253     // Set the content type
00254     USES_CONVERSION;
00255     put_PluginContentType(T2OLE(pszContentType));
00256 
00257     // Search for a plugin that can handle this content
00258     HRESULT hr = FindPluginPathByContentType(pszContentType, &pszPluginPath);
00259     if (FAILED(hr))
00260     {
00261         // Try the default 'catch-all' plugin
00262         hr = FindPluginPathByContentType(_T("*"), &pszPluginPath);
00263         if (FAILED(hr))
00264         {
00265             return hr;
00266         }
00267     }
00268 
00269     hr = LoadPlugin(pszPluginPath);
00270     free(pszPluginPath);
00271 
00272     return hr;
00273 }
00274 
00275 HRESULT nsPluginHostCtrl::CreatePluginList(unsigned long ulFlags)
00276 {
00277     // This function trawls through the plugin directory and builds a list
00278     // of plugins and what MIME types each plugin handles.
00279 
00280     CleanupPluginList();
00281 
00282     // Try and obtain a path to the plugins in Netscape 6.x or Mozilla
00283     if (ulFlags & PLUGINS_FROM_NS6X ||
00284         ulFlags & PLUGINS_FROM_MOZILLA)
00285     {
00286         // TODO search for Mozilla/NS 6.x plugins dir
00287     }
00288 
00289     // Try and obtain a path to the plugins in Netscape 4.x
00290     if (ulFlags & PLUGINS_FROM_NS4X)
00291     {
00292         TCHAR szPluginsDir[_MAX_PATH];
00293         memset(szPluginsDir, 0, sizeof(szPluginsDir));
00294         
00295         CRegKey keyNS;
00296         const TCHAR *kNav4xKey = _T("Software\\Netscape\\Netscape Navigator");
00297         if (keyNS.Open(HKEY_LOCAL_MACHINE, kNav4xKey, KEY_READ) == ERROR_SUCCESS)
00298         {
00299             TCHAR szVersion[10];
00300             DWORD nVersion = sizeof(szVersion) / sizeof(szVersion[0]);
00301             keyNS.QueryValue(szVersion, _T("CurrentVersion"), &nVersion);
00302         
00303             CRegKey keyVersion;
00304             if (keyVersion.Open(keyNS, szVersion, KEY_READ) == ERROR_SUCCESS)
00305             {
00306                 CRegKey keyMain;
00307                 if (keyMain.Open(keyVersion, _T("Main"), KEY_READ) == ERROR_SUCCESS)
00308                 {
00309                     DWORD nPluginsDir = sizeof(szPluginsDir) / sizeof(szPluginsDir[0]);
00310                     keyMain.QueryValue(szPluginsDir, _T("Plugins Directory"), &nPluginsDir);
00311                     keyMain.Close();
00312                 }
00313                 keyVersion.Close();
00314             }
00315             keyNS.Close();
00316         }
00317         if (szPluginsDir[0])
00318         {
00319             CreatePluginListFrom(szPluginsDir);
00320         }
00321     }
00322 
00323     // Try and obtain a path to the plugins in Internet Explorer
00324     if (ulFlags & PLUGINS_FROM_IE)
00325     {
00326         TCHAR szPluginsDir[_MAX_PATH];
00327         memset(szPluginsDir, 0, sizeof(szPluginsDir));
00328 
00329         CRegKey keyIE;
00330         const TCHAR *kIEKey = _T("Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\IEXPLORE.EXE");
00331         if (keyIE.Open(HKEY_LOCAL_MACHINE, kIEKey, KEY_READ) == ERROR_SUCCESS)
00332         {
00333             DWORD nPluginsDir = sizeof(szPluginsDir) / sizeof(szPluginsDir[0]);
00334             keyIE.QueryValue(szPluginsDir, _T("Path"), &nPluginsDir);
00335 
00336             TCHAR *szSemiColon = _tcschr(szPluginsDir, _TCHAR(';'));
00337             if (szSemiColon)
00338             {
00339                 *szSemiColon = _TCHAR('\0');
00340             }
00341 
00342             ULONG nLen = _tcslen(szPluginsDir);
00343             if (nLen > 0 && szPluginsDir[nLen - 1] == _TCHAR('\\'))
00344             {
00345                 szPluginsDir[nLen - 1] = _TCHAR('\0');
00346             }
00347             _tcscat(szPluginsDir, _T("\\Plugins"));
00348 
00349             keyIE.Close();
00350         }
00351         if (szPluginsDir[0])
00352         {
00353             CreatePluginListFrom(szPluginsDir);
00354         }
00355     }
00356 
00357     return S_OK;
00358 }
00359 
00360 HRESULT nsPluginHostCtrl::CreatePluginListFrom(const TCHAR *szPluginsDir)
00361 {
00362     HANDLE hFind;
00363     WIN32_FIND_DATA finddata;
00364 
00365     // Change to the plugin directory
00366     TCHAR szCurrentDir[MAX_PATH + 1];
00367     GetCurrentDirectory(sizeof(szCurrentDir) / sizeof(szCurrentDir[0]), szCurrentDir);
00368     SetCurrentDirectory(szPluginsDir);
00369 
00370     // Search for files matching the "np*dll" pattern
00371     hFind = FindFirstFile(_T("np*dll"), &finddata);
00372     if (hFind != INVALID_HANDLE_VALUE)
00373     {
00374         do {
00375             PluginInfo *pInfo = new PluginInfo;
00376             if (!pInfo)
00377             {
00378                 CleanupPluginList();
00379                 SetCurrentDirectory(szCurrentDir);
00380                 return E_OUTOFMEMORY;
00381             }
00382             if (SUCCEEDED(GetPluginInfo(finddata.cFileName, pInfo)))
00383             {
00384                 pInfo->szPluginName = _tcsdup(finddata.cFileName);
00385                 pInfo->szPluginPath = _tcsdup(szPluginsDir);
00386                 m_Plugins.AppendElement(pInfo);
00387             }
00388             else
00389             {
00390                 ATLTRACE(_T("Error: Cannot plugin info for \"%s\".\n"), finddata.cFileName);
00391                 delete pInfo;
00392             }
00393         } while (FindNextFile(hFind, &finddata));
00394         FindClose(hFind);
00395     }
00396 
00397     SetCurrentDirectory(szCurrentDir);
00398 
00399     return S_OK;
00400 }
00401 
00402 
00403 HRESULT nsPluginHostCtrl::CleanupPluginList()
00404 {
00405     // Free the memory used by the plugin info list
00406     for (unsigned long i = 0; i < m_Plugins.Count(); i++)
00407     {
00408         PluginInfo *pI = m_Plugins[i];
00409         if (pI->szMIMEType)
00410             free(pI->szMIMEType);
00411         if (pI->szPluginName)
00412             free(pI->szPluginName);
00413         if (pI->szPluginPath)
00414             free(pI->szPluginPath);
00415         free(pI);
00416     }
00417     m_Plugins.Empty();
00418     return S_OK;
00419 }
00420 
00421 
00422 HRESULT nsPluginHostCtrl::GetPluginInfo(const TCHAR *pszPluginPath, PluginInfo *pInfo)
00423 {
00424     // Get the version info from the plugin
00425     USES_CONVERSION;
00426     DWORD nVersionInfoSize;
00427     DWORD nZero = 0;
00428     void *pVersionInfo = NULL;
00429     nVersionInfoSize = GetFileVersionInfoSize((TCHAR *)pszPluginPath, &nZero);
00430     if (nVersionInfoSize)
00431     {
00432         pVersionInfo = malloc(nVersionInfoSize);
00433     }
00434     if (!pVersionInfo)
00435     {
00436         return E_OUTOFMEMORY;
00437     }
00438 
00439     GetFileVersionInfo((TCHAR *)pszPluginPath, NULL, nVersionInfoSize, pVersionInfo);
00440 
00441     // Extract the MIMEType info
00442     TCHAR *szValue = NULL;
00443     UINT nValueLength = 0;
00444     if (!VerQueryValue(pVersionInfo,
00445         _T("\\StringFileInfo\\040904E4\\MIMEType"),
00446         (void **) &szValue, &nValueLength))
00447     {
00448         return E_FAIL;
00449     }
00450 
00451     if (pInfo)
00452     {
00453         pInfo->szMIMEType = _tcsdup(szValue);
00454     }
00455 
00456     free(pVersionInfo);
00457 
00458     return S_OK;
00459 }
00460 
00461 HRESULT nsPluginHostCtrl::FindPluginPathByContentType(const TCHAR *pszContentType, TCHAR **ppszPluginPath)
00462 {
00463     *ppszPluginPath = NULL;
00464 
00465     if (pszContentType == NULL)
00466     {
00467         return E_FAIL;
00468     }
00469 
00470     // Search the list of plugins for one that will handle the content type
00471     TCHAR szPluginPath[_MAX_PATH + 1];
00472     unsigned long nContentType = _tcslen(pszContentType);
00473     for (unsigned long i = 0; i < m_Plugins.Count(); i++)
00474     {
00475         PluginInfo *pI = m_Plugins[i];
00476         if (pI->szMIMEType)
00477         {
00478             TCHAR *pszMIMEType = pI->szMIMEType;
00479             do {
00480                 if (_tcsncmp(pszContentType, pszMIMEType, nContentType) == 0)
00481                 {
00482                     // Found a match
00483                     _tmakepath(szPluginPath, NULL,
00484                         pI->szPluginPath, pI->szPluginName, NULL);
00485                     *ppszPluginPath = _tcsdup(szPluginPath);
00486                     return S_OK;
00487                 }
00488                 // Check the other types the plugin handles
00489                 pszMIMEType = _tcschr(pszMIMEType, TCHAR('|'));
00490                 if (pszMIMEType)
00491                 {
00492                     pszMIMEType++;
00493                 }
00494             } while (pszMIMEType && *pszMIMEType);
00495         }
00496     }
00497 
00498     return E_FAIL;
00499 }
00500 
00501 HRESULT nsPluginHostCtrl::LoadPlugin(const TCHAR *szPluginPath)
00502 {
00503     ATLASSERT(m_pLoadedPlugin == NULL);
00504     if (m_pLoadedPlugin)
00505     {
00506         return E_UNEXPECTED;
00507     }
00508 
00509     // TODO critical section
00510 
00511     // Test if the plugin has already been loaded
00512     for (unsigned long i = 0; i < m_LoadedPlugins.Count(); i++)
00513     {
00514         if (_tcscmp(m_LoadedPlugins[i]->szFullPath, szPluginPath) == 0)
00515         {
00516             m_pLoadedPlugin = m_LoadedPlugins[i];
00517             memcpy(&m_NPPFuncs, &m_pLoadedPlugin->NPPFuncs, sizeof(m_NPPFuncs));
00518             m_pLoadedPlugin->nRefCount++;
00519             return S_OK;
00520         }
00521     }
00522 
00523     // Plugin library is being loaded for the first time so initialise it
00524     // and store an entry in the loaded plugins array.
00525 
00526     HINSTANCE hInstance = LoadLibrary(szPluginPath);
00527     if (!hInstance)
00528     {
00529         return E_FAIL;
00530     }
00531 
00532     m_pLoadedPlugin = new LoadedPluginInfo;
00533     if (!m_pLoadedPlugin)
00534     {
00535         ATLASSERT(m_pLoadedPlugin);
00536         return E_OUTOFMEMORY;
00537     }
00538 
00539     // Get the plugin function entry points
00540     NP_GETENTRYPOINTS pfnGetEntryPoints =
00541         (NP_GETENTRYPOINTS) GetProcAddress(hInstance, "NP_GetEntryPoints");
00542     if (pfnGetEntryPoints)
00543     {
00544         pfnGetEntryPoints(&m_NPPFuncs);
00545     }
00546 
00547     // Tell the plugin to initialize itself
00548     NP_PLUGININIT pfnInitialize = (NP_PLUGININIT)
00549         GetProcAddress(hInstance, "NP_Initialize");
00550     if (!pfnInitialize)
00551     {
00552         pfnInitialize = (NP_PLUGININIT)
00553             GetProcAddress(hInstance, "NP_PluginInit");
00554     }
00555     if (pfnInitialize)
00556     {
00557         pfnInitialize(&g_NPNFuncs);
00558     }
00559 
00560     // Create a new entry for the plugin
00561     m_pLoadedPlugin->szFullPath = _tcsdup(szPluginPath);
00562     m_pLoadedPlugin->nRefCount = 1;
00563     m_pLoadedPlugin->hInstance = hInstance;
00564     memcpy(&m_pLoadedPlugin->NPPFuncs, &m_NPPFuncs, sizeof(m_NPPFuncs));
00565 
00566     // Add it to the array
00567     m_LoadedPlugins.AppendElement(m_pLoadedPlugin);
00568 
00569     return S_OK;
00570 }
00571 
00572 HRESULT nsPluginHostCtrl::UnloadPlugin()
00573 {
00574     if (!m_pLoadedPlugin)
00575     {
00576         return E_FAIL;
00577     }
00578 
00579     // TODO critical section
00580 
00581     ATLASSERT(m_pLoadedPlugin->nRefCount > 0);
00582     if (m_pLoadedPlugin->nRefCount == 1)
00583     {
00584         NP_PLUGINSHUTDOWN pfnShutdown = (NP_PLUGINSHUTDOWN)
00585             GetProcAddress(
00586                 m_pLoadedPlugin->hInstance,
00587                 "NP_Shutdown");
00588         if (pfnShutdown)
00589         {
00590             pfnShutdown();
00591         }
00592         FreeLibrary(m_pLoadedPlugin->hInstance);
00593 
00594         // Delete the entry from the array
00595         m_LoadedPlugins.RemoveElement(m_pLoadedPlugin);
00596         free(m_pLoadedPlugin->szFullPath);
00597         delete m_pLoadedPlugin;
00598     }
00599     else
00600     {
00601         m_pLoadedPlugin->nRefCount--;
00602     }
00603 
00604     m_pLoadedPlugin = NULL;
00605 
00606     return S_OK;
00607 }
00608 
00609 
00610 HRESULT nsPluginHostCtrl::AddPluginParam(const char *szName, const char *szValue)
00611 {
00612     ATLASSERT(szName);
00613     ATLASSERT(szValue);
00614     if (!szName || !szValue)
00615     {
00616         return E_INVALIDARG;
00617     }
00618 
00619     // Skip params that already there
00620     for (unsigned long i = 0; i < m_nArgs; i++)
00621     {
00622         if (stricmp(szName, m_pszArgNames[i]) == 0)
00623         {
00624             return S_OK;
00625         }
00626     }
00627 
00628     // Add the value
00629     if (!m_pszArgNames)
00630     {
00631         ATLASSERT(!m_pszArgValues);
00632         m_nArgsMax = kArraySizeIncrement;
00633         m_pszArgNames = (char **) malloc(sizeof(char *) * m_nArgsMax);
00634         m_pszArgValues = (char **) malloc(sizeof(char *) * m_nArgsMax);
00635     }
00636     else if (m_nArgs == m_nArgsMax)
00637     {
00638         m_nArgsMax += kArraySizeIncrement;
00639         m_pszArgNames = (char **) realloc(m_pszArgNames, sizeof(char *) * m_nArgsMax);
00640         m_pszArgValues = (char **) realloc(m_pszArgValues, sizeof(char *) * m_nArgsMax);
00641     }
00642     if (!m_pszArgNames || !m_pszArgValues)
00643     {
00644         return E_OUTOFMEMORY;
00645     }
00646 
00647     m_pszArgNames[m_nArgs] = strdup(szName);
00648     m_pszArgValues[m_nArgs] = strdup(szValue);
00649 
00650     m_nArgs++;
00651     
00652     return S_OK;
00653 }
00654 
00655 
00656 HRESULT nsPluginHostCtrl::CreatePluginInstance()
00657 {
00658     m_NPP.pdata = NULL;
00659     m_NPP.ndata = this;
00660 
00661     USES_CONVERSION;
00662     char *szContentType = strdup(OLE2A(m_bstrContentType.m_str));
00663 
00664     // Create a child window to house the plugin
00665     RECT rc;
00666     GetClientRect(&rc);
00667     m_wndPlugin.Create(m_hWnd, rc, NULL, WS_CHILD | WS_VISIBLE);
00668 
00669     m_NPWindow.window = (void *) m_wndPlugin.m_hWnd;
00670     m_NPWindow.type = NPWindowTypeWindow;
00671 
00672     if (m_NPPFuncs.newp)
00673     {
00674         // Create the arguments to be fed into the plugin
00675         if (m_bstrSource.m_str)
00676         {
00677             AddPluginParam("SRC", OLE2A(m_bstrSource.m_str));
00678         }
00679         if (m_bstrContentType.m_str)
00680         {
00681             AddPluginParam("TYPE", OLE2A(m_bstrContentType.m_str));
00682         }
00683         if (m_bstrPluginsPage.m_str)
00684         {
00685             AddPluginParam("PLUGINSPAGE", OLE2A(m_bstrPluginsPage.m_str));
00686         }
00687         char szTmp[50];
00688         sprintf(szTmp, "%d", (int) (rc.right - rc.left));
00689         AddPluginParam("WIDTH", szTmp);
00690         sprintf(szTmp, "%d", (int) (rc.bottom - rc.top));
00691         AddPluginParam("HEIGHT", szTmp);
00692 
00693         NPSavedData *pSaved = NULL;
00694 
00695         // Create the plugin instance
00696         NPError npres = m_NPPFuncs.newp(szContentType, &m_NPP, NP_EMBED,
00697             (short) m_nArgs, m_pszArgNames, m_pszArgValues, pSaved);
00698 
00699         if (npres != NPERR_NO_ERROR)
00700         {
00701             return E_FAIL;
00702         }
00703     }
00704 
00705     m_bPluginIsAlive = TRUE;
00706 
00707     SizeToFitPluginInstance();
00708 
00709     return S_OK;
00710 }
00711 
00712 HRESULT nsPluginHostCtrl::DestroyPluginInstance()
00713 {
00714     if (!m_bPluginIsAlive)
00715     {
00716         return S_OK;
00717     }
00718 
00719     // Destroy the plugin
00720     if (m_NPPFuncs.destroy)
00721     {
00722         NPSavedData *pSavedData = NULL;
00723         NPError npres = m_NPPFuncs.destroy(&m_NPP, &pSavedData);
00724 
00725         // TODO could store saved data instead of just deleting it.
00726         if (pSavedData && pSavedData->buf)
00727         {
00728             NPN_MemFree(pSavedData->buf);
00729         }
00730     }
00731 
00732     // Destroy the arguments
00733     if (m_pszArgNames)
00734     {
00735         for (unsigned long i = 0; i < m_nArgs; i++)
00736         {
00737             free(m_pszArgNames[i]);
00738         }
00739         free(m_pszArgNames);
00740         m_pszArgNames = NULL;
00741     }
00742     if (m_pszArgValues)
00743     {
00744         for (unsigned long i = 0; i < m_nArgs; i++)
00745         {
00746             free(m_pszArgValues[i]);
00747         }
00748         free(m_pszArgValues);
00749         m_pszArgValues = NULL;
00750     }
00751 
00752     m_wndPlugin.DestroyWindow();
00753 
00754     m_bPluginIsAlive = FALSE;
00755 
00756     return S_OK;
00757 }
00758 
00759 HRESULT nsPluginHostCtrl::SizeToFitPluginInstance()
00760 {
00761     if (!m_bPluginIsAlive)
00762     {
00763         return S_OK;
00764     }
00765 
00766     // Resize the plugin to fit the window
00767 
00768     RECT rc;
00769     GetClientRect(&rc);
00770 
00771     m_wndPlugin.SetWindowPos(HWND_TOP,
00772         rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
00773         SWP_NOZORDER);
00774     
00775     m_NPWindow.x = 0;
00776     m_NPWindow.y = 0;
00777     m_NPWindow.width = rc.right - rc.left;
00778     m_NPWindow.height = rc.bottom - rc.top;
00779     m_NPWindow.clipRect.left = 0;
00780     m_NPWindow.clipRect.top = 0;
00781     m_NPWindow.clipRect.right = m_NPWindow.width;
00782     m_NPWindow.clipRect.bottom = m_NPWindow.height;
00783 
00784     if (m_NPPFuncs.setwindow)
00785     {
00786        NPError npres = m_NPPFuncs.setwindow(&m_NPP, &m_NPWindow);
00787     }
00788 
00789     return S_OK;
00790 }
00791 
00792 HRESULT nsPluginHostCtrl::OpenURLStream(const TCHAR *szURL, void *pNotifyData, const void *pPostData, unsigned long nPostDataLength)
00793 {
00794     nsURLDataCallback::OpenURL(this, szURL, pNotifyData, pPostData, nPostDataLength);
00795     return S_OK;
00796 }
00797 
00799 // IMozPluginHostCtrl
00800 
00801 STDMETHODIMP nsPluginHostCtrl::Load(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog)
00802 {
00803     CComQIPtr<IPropertyBag2> cpPropBag2 = pPropBag;
00804     if (cpPropBag2)
00805     {
00806         // Read *all* the properties via IPropertyBag2 and store them somewhere
00807         // so they can be fed into the plugin instance at creation..
00808         ULONG nProperties;
00809         cpPropBag2->CountProperties(&nProperties);
00810         if (nProperties > 0)
00811         {
00812             PROPBAG2 *pProperties = (PROPBAG2 *) malloc(sizeof(PROPBAG2) * nProperties);
00813             ULONG nPropertiesGotten = 0;
00814             cpPropBag2->GetPropertyInfo(0, nProperties, pProperties, &nPropertiesGotten);
00815             for (ULONG i = 0; i < nPropertiesGotten; i++)
00816             {
00817                 if (pProperties[i].vt == VT_BSTR)
00818                 {
00819                     USES_CONVERSION;
00820                     CComVariant v;
00821                     HRESULT hrRead;
00822                     cpPropBag2->Read(1, &pProperties[i], NULL, &v, &hrRead);
00823                     AddPluginParam(OLE2A(pProperties[i].pstrName), OLE2A(v.bstrVal));
00824                 }
00825                 if (pProperties[i].pstrName)
00826                 {
00827                     CoTaskMemFree(pProperties[i].pstrName);
00828                 }
00829             }
00830             free(pProperties);
00831         }
00832     }
00833     return IPersistPropertyBagImpl<nsPluginHostCtrl>::Load(pPropBag, pErrorLog);
00834 }
00835 
00837 // IMozPluginHostCtrl
00838 
00839 STDMETHODIMP nsPluginHostCtrl::get_PluginContentType(BSTR *pVal)
00840 {
00841     if (!pVal)
00842     {
00843         return E_INVALIDARG;
00844     }
00845     *pVal = m_bstrContentType.Copy();
00846        return S_OK;
00847 }
00848 
00849 STDMETHODIMP nsPluginHostCtrl::put_PluginContentType(BSTR newVal)
00850 {
00851     // Security. Copying the source BSTR this way ensures that embedded NULL
00852     // characters do not end up in the destination BSTR. SysAllocString will
00853     // create a copy truncated at the first NULL char.
00854     m_bstrContentType.Empty();
00855     m_bstrContentType.Attach(SysAllocString(newVal));
00856        return S_OK;
00857 }
00858 
00859 STDMETHODIMP nsPluginHostCtrl::get_PluginSource(BSTR *pVal)
00860 {
00861     if (!pVal)
00862     {
00863         return E_INVALIDARG;
00864     }
00865     *pVal = m_bstrSource.Copy();
00866        return S_OK;
00867 }
00868 
00869 STDMETHODIMP nsPluginHostCtrl::put_PluginSource(BSTR newVal)
00870 {
00871     // Security. Copying the source BSTR this way ensures that embedded NULL
00872     // characters do not end up in the destination BSTR. SysAllocString will
00873     // create a copy truncated at the first NULL char.
00874     m_bstrSource.Empty();
00875     m_bstrSource.Attach(SysAllocString(newVal));
00876        return S_OK;
00877 }
00878 
00879 STDMETHODIMP nsPluginHostCtrl::get_PluginsPage(BSTR *pVal)
00880 {
00881     if (!pVal)
00882     {
00883         return E_INVALIDARG;
00884     }
00885     *pVal = m_bstrPluginsPage.Copy();
00886        return S_OK;
00887 }
00888 
00889 STDMETHODIMP nsPluginHostCtrl::put_PluginsPage(BSTR newVal)
00890 {
00891     // Security. Copying the source BSTR this way ensures that embedded NULL
00892     // characters do not end up in the destination BSTR. SysAllocString will
00893     // create a copy truncated at the first NULL char.
00894     m_bstrPluginsPage.Empty();
00895     m_bstrPluginsPage.Attach(SysAllocString(newVal));
00896        return S_OK;
00897 }