/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Netscape security libraries. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1994-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Adam Lock * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "stdafx.h" #include "nsPluginHostWnd.h" #include "nsURLDataCallback.h" #include "npn.h" #define NS_4XPLUGIN_CALLBACK(_type, _name) _type (__stdcall * _name) typedef NS_4XPLUGIN_CALLBACK(NPError, NP_GETENTRYPOINTS) (NPPluginFuncs* pCallbacks); typedef NS_4XPLUGIN_CALLBACK(NPError, NP_PLUGININIT) (const NPNetscapeFuncs* pCallbacks); typedef NS_4XPLUGIN_CALLBACK(NPError, NP_PLUGINSHUTDOWN) (void); const kArraySizeIncrement = 10; nsSimpleArray nsPluginHostWnd::m_LoadedPlugins; nsPluginHostWnd::nsPluginHostWnd() : m_bPluginIsAlive(false), m_bCreatePluginFromStreamData(false), m_bPluginIsWindowless(false), m_bPluginIsTransparent(false), m_pLoadedPlugin(NULL), m_nArgs(0), m_nArgsMax(0), m_pszArgNames(NULL), m_pszArgValues(NULL) { InitPluginCallbacks(); memset(&m_NPPFuncs, 0, sizeof(m_NPPFuncs)); } nsPluginHostWnd::~nsPluginHostWnd() { } LRESULT nsPluginHostWnd::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { SetWindowLong(GWL_STYLE, GetWindowLong(GWL_STYLE) | WS_CLIPCHILDREN); // Load a list of plugins CreatePluginList( PLUGINS_FROM_IE | PLUGINS_FROM_NS4X | PLUGINS_FROM_FIREFOX | PLUGINS_FROM_MOZILLA); HRESULT hr = E_FAIL; if (m_bstrContentType.Length() == 0 && m_bstrSource.Length() != 0) { USES_CONVERSION; // Do a late instantiation of the plugin based on the content type of // the stream data. m_bCreatePluginFromStreamData = true; hr = OpenURLStream(OLE2T(m_bstrSource), NULL, NULL, 0); } else { // Create a plugin based upon the specified content type property USES_CONVERSION; hr = LoadPluginByContentType(OLE2T(m_bstrContentType)); if (SUCCEEDED(hr)) { hr = CreatePluginInstance(); if (m_bstrSource.Length()) { OpenURLStream(OLE2T(m_bstrSource), NULL, NULL, 0); } } } return SUCCEEDED(hr) ? 0 : -1; } LRESULT nsPluginHostWnd::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { DestroyPluginInstance(); UnloadPlugin(); CleanupPluginList(); return 0; } LRESULT nsPluginHostWnd::OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { SizeToFitPluginInstance(); return 0; } LRESULT nsPluginHostWnd::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { PAINTSTRUCT ps; HDC hdc = BeginPaint(&ps); RECT rc; GetClientRect(&rc); if (m_bPluginIsWindowless && m_NPPFuncs.event) { if (this->m_bPluginIsTransparent) { int x = 0; const int inc = 20; for (int i = rc.left; i < rc.right; i += inc) { const COLORREF c1 = RGB(255, 120, 120); const COLORREF c2 = RGB(120, 120, 255); RECT rcStrip = rc; HBRUSH hbr = CreateSolidBrush(x % 2 ? c1 : c2); rcStrip.left = i; rcStrip.right = i + inc; FillRect(hdc, &rcStrip, hbr); DeleteObject(hbr); x++; } } else { FillRect(hdc, &rc, (HBRUSH) GetStockObject(GRAY_BRUSH)); } m_NPWindow.type = NPWindowTypeDrawable; m_NPWindow.window = hdc; m_NPWindow.x = 0; m_NPWindow.y = 0; m_NPWindow.width = rc.right - rc.left; m_NPWindow.height = rc.bottom - rc.top; m_NPWindow.clipRect.left = 0; m_NPWindow.clipRect.top = 0; m_NPWindow.clipRect.right = m_NPWindow.width; m_NPWindow.clipRect.bottom = m_NPWindow.height; if (m_NPPFuncs.setwindow) { NPError npres = m_NPPFuncs.setwindow(&m_NPP, &m_NPWindow); } NPRect paintRect; paintRect.left = rc.left; paintRect.top = rc.top; paintRect.right = rc.right; paintRect.bottom = rc.bottom; NPEvent evt; evt.event = WM_PAINT; evt.wParam = wParam; evt.lParam = (LPARAM) &paintRect; m_NPPFuncs.event(&m_NPP, &evt); } else { FillRect(hdc, &rc, (HBRUSH) GetStockObject(GRAY_BRUSH)); } EndPaint(&ps); return 0; } LRESULT nsPluginHostWnd::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { if (m_bPluginIsWindowless && m_NPPFuncs.event) { NPEvent evt; evt.event = uMsg; evt.wParam = wParam; evt.lParam = lParam; m_NPPFuncs.event(&m_NPP, &evt); } return 0; } LRESULT nsPluginHostWnd::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { if (m_bPluginIsWindowless && m_NPPFuncs.event) { NPEvent evt; evt.event = uMsg; evt.wParam = wParam; evt.lParam = lParam; m_NPPFuncs.event(&m_NPP, &evt); } return 0; } LRESULT nsPluginHostWnd::OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) { if (m_bPluginIsWindowless && m_NPPFuncs.event) { NPEvent evt; evt.event = uMsg; evt.wParam = wParam; evt.lParam = lParam; m_NPPFuncs.event(&m_NPP, &evt); } return 0; } /////////////////////////////////////////////////////////////////////////////// NPNetscapeFuncs nsPluginHostWnd::g_NPNFuncs; HRESULT nsPluginHostWnd::InitPluginCallbacks() { static BOOL gCallbacksSet = FALSE; if (gCallbacksSet) { return S_OK; } gCallbacksSet = TRUE; memset(&g_NPNFuncs, 0, sizeof(g_NPNFuncs)); g_NPNFuncs.size = sizeof(g_NPNFuncs); g_NPNFuncs.version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR; g_NPNFuncs.geturl = NewNPN_GetURLProc(NPN_GetURL); g_NPNFuncs.posturl = NewNPN_PostURLProc(NPN_PostURL); g_NPNFuncs.requestread = NewNPN_RequestReadProc(NPN_RequestRead); g_NPNFuncs.newstream = NewNPN_NewStreamProc(NPN_NewStream); g_NPNFuncs.write = NewNPN_WriteProc(NPN_Write); g_NPNFuncs.destroystream = NewNPN_DestroyStreamProc(NPN_DestroyStream); g_NPNFuncs.status = NewNPN_StatusProc(NPN_Status); g_NPNFuncs.uagent = NewNPN_UserAgentProc(NPN_UserAgent); g_NPNFuncs.memalloc = NewNPN_MemAllocProc(NPN_MemAlloc); g_NPNFuncs.memfree = NewNPN_MemFreeProc(NPN_MemFree); g_NPNFuncs.memflush = NewNPN_MemFlushProc(NPN_MemFlush); g_NPNFuncs.reloadplugins = NewNPN_ReloadPluginsProc(NPN_ReloadPlugins); g_NPNFuncs.getJavaEnv = NewNPN_GetJavaEnvProc(NPN_GetJavaEnv); g_NPNFuncs.getJavaPeer = NewNPN_GetJavaPeerProc(NPN_GetJavaPeer); g_NPNFuncs.geturlnotify = NewNPN_GetURLNotifyProc(NPN_GetURLNotify); g_NPNFuncs.posturlnotify = NewNPN_PostURLNotifyProc(NPN_PostURLNotify); g_NPNFuncs.getvalue = NewNPN_GetValueProc(NPN_GetValue); g_NPNFuncs.setvalue = NewNPN_SetValueProc(NPN_SetValue); g_NPNFuncs.invalidaterect = NewNPN_InvalidateRectProc(NPN_InvalidateRect); g_NPNFuncs.invalidateregion = NewNPN_InvalidateRegionProc(NPN_InvalidateRegion); g_NPNFuncs.forceredraw = NewNPN_ForceRedrawProc(NPN_ForceRedraw); return S_OK; } HRESULT nsPluginHostWnd::GetWebBrowserApp(IWebBrowserApp **pBrowser) { // Override this method if there is a way to get this iface ATLASSERT(pBrowser); if (!pBrowser) { return E_INVALIDARG; } *pBrowser = NULL; return S_OK; } void nsPluginHostWnd::SetPluginWindowless(bool bWindowless) { m_bPluginIsWindowless = bWindowless; } void nsPluginHostWnd::SetPluginTransparent(bool bTransparent) { m_bPluginIsTransparent = bTransparent; } HRESULT nsPluginHostWnd::GetBaseURL(TCHAR **ppszBaseURL) { ATLASSERT(ppszBaseURL); *ppszBaseURL = NULL; CComPtr cpWebBrowser; GetWebBrowserApp(&cpWebBrowser); if (!cpWebBrowser) { return E_FAIL; } USES_CONVERSION; CComBSTR bstrURL; cpWebBrowser->get_LocationURL(&bstrURL); DWORD cbBaseURL = (bstrURL.Length() + 1) * sizeof(WCHAR); DWORD cbBaseURLUsed = 0; WCHAR *pszBaseURL = (WCHAR *) malloc(cbBaseURL); ATLASSERT(pszBaseURL); CoInternetParseUrl( bstrURL.m_str, PARSE_ROOTDOCUMENT, 0, pszBaseURL, cbBaseURL, &cbBaseURLUsed, 0); *ppszBaseURL = _tcsdup(W2T(pszBaseURL)); free(pszBaseURL); return S_OK; } HRESULT nsPluginHostWnd::LoadPluginByContentType(const TCHAR *pszContentType) { TCHAR * pszPluginPath = NULL; // Set the content type USES_CONVERSION; SetPluginContentType(T2OLE(pszContentType)); // Search for a plugin that can handle this content HRESULT hr = FindPluginPathByContentType(pszContentType, &pszPluginPath); if (FAILED(hr)) { // Try the default 'catch-all' plugin hr = FindPluginPathByContentType(_T("*"), &pszPluginPath); if (FAILED(hr)) { return hr; } } hr = LoadPlugin(pszPluginPath); free(pszPluginPath); return hr; } HRESULT nsPluginHostWnd::GetPluginContentType(BSTR *pVal) { if (!pVal) { return E_INVALIDARG; } *pVal = m_bstrContentType.Copy(); return S_OK; } HRESULT nsPluginHostWnd::SetPluginContentType(BSTR newVal) { // Security. Copying the source BSTR this way ensures that embedded NULL // characters do not end up in the destination BSTR. SysAllocString will // create a copy truncated at the first NULL char. m_bstrContentType.Empty(); m_bstrContentType.Attach(SysAllocString(newVal)); return S_OK; } HRESULT nsPluginHostWnd::GetPluginSource(BSTR *pVal) { if (!pVal) { return E_INVALIDARG; } *pVal = m_bstrSource.Copy(); return S_OK; } HRESULT nsPluginHostWnd::SetPluginSource(BSTR newVal) { // Security. Copying the source BSTR this way ensures that embedded NULL // characters do not end up in the destination BSTR. SysAllocString will // create a copy truncated at the first NULL char. m_bstrSource.Empty(); m_bstrSource.Attach(SysAllocString(newVal)); return S_OK; } HRESULT nsPluginHostWnd::GetPluginsPage(BSTR *pVal) { if (!pVal) { return E_INVALIDARG; } *pVal = m_bstrPluginsPage.Copy(); return S_OK; } HRESULT nsPluginHostWnd::SetPluginsPage(BSTR newVal) { // Security. Copying the source BSTR this way ensures that embedded NULL // characters do not end up in the destination BSTR. SysAllocString will // create a copy truncated at the first NULL char. m_bstrPluginsPage.Empty(); m_bstrPluginsPage.Attach(SysAllocString(newVal)); return S_OK; } HRESULT nsPluginHostWnd::ReadPluginsFromGeckoAppPath(const TCHAR *szAppName) { const TCHAR szGeneralKey[] = _T("SOFTWARE\\Mozilla\\"); const size_t nGeneralKeyLen = sizeof(szGeneralKey) / sizeof(TCHAR); const size_t nMainKeyLen = nGeneralKeyLen + _tcslen(szAppName); TCHAR *szMainKey = new TCHAR[nMainKeyLen]; memset(szMainKey, 0, nMainKeyLen * sizeof(TCHAR)); _tcscpy(szMainKey, szGeneralKey); _tcscat(szMainKey, szAppName); CRegKey keyGeneral; if (keyGeneral.Open(HKEY_LOCAL_MACHINE, szMainKey, KEY_READ) == ERROR_SUCCESS) { // First find the Current Version TCHAR szVersion[64]; const size_t nVersionLen = sizeof(szVersion) / sizeof(szVersion[0]); memset(szVersion, 0, sizeof(szVersion)); DWORD nVersion = nVersionLen; keyGeneral.QueryStringValue(_T("CurrentVersion"), szVersion, &nVersion); if (nVersion > 0) { TCHAR *szBracket = _tcschr(szVersion, TCHAR('(')); if (szBracket) { while (szBracket >= szVersion) { if (*szBracket == TCHAR(' ') || *szBracket == TCHAR('(')) { *szBracket = TCHAR('\0'); szBracket--; } else break; } } nVersion = _tcslen(szVersion); TCHAR *szKey = new TCHAR[nMainKeyLen + nVersion + 32]; _tcscpy(szKey, szMainKey); _tcscat(szKey, _T(" ")); _tcscat(szKey, szVersion); _tcscat(szKey, _T("\\Extensions")); CRegKey key; if (key.Open(HKEY_LOCAL_MACHINE, szKey, KEY_READ) == ERROR_SUCCESS) { TCHAR szPluginsDir[_MAX_PATH]; memset(szPluginsDir, 0, sizeof(szPluginsDir)); DWORD nPluginsDir = sizeof(szPluginsDir) / sizeof(szPluginsDir[0]); key.QueryStringValue(_T("Plugins"), szPluginsDir, &nPluginsDir); if (szPluginsDir[0]) { CreatePluginListFrom(szPluginsDir); } } delete []szKey; } } delete []szMainKey; return S_OK; } HRESULT nsPluginHostWnd::CreatePluginList(unsigned long ulFlags) { // This function trawls through the plugin directory and builds a list // of plugins and what MIME types each plugin handles. CleanupPluginList(); // Firefox if (ulFlags & PLUGINS_FROM_FIREFOX) { ReadPluginsFromGeckoAppPath(_T("Mozilla Firefox")); } // Mozilla if (ulFlags & PLUGINS_FROM_MOZILLA) { ReadPluginsFromGeckoAppPath(_T("Mozilla")); } // Try and obtain a path to the plugins in Netscape 4.x if (ulFlags & PLUGINS_FROM_NS4X) { TCHAR szPluginsDir[_MAX_PATH]; memset(szPluginsDir, 0, sizeof(szPluginsDir)); CRegKey keyNS; const TCHAR *kNav4xKey = _T("Software\\Netscape\\Netscape Navigator"); if (keyNS.Open(HKEY_LOCAL_MACHINE, kNav4xKey, KEY_READ) == ERROR_SUCCESS) { TCHAR szVersion[10]; DWORD nVersion = sizeof(szVersion) / sizeof(szVersion[0]); keyNS.QueryValue(szVersion, _T("CurrentVersion"), &nVersion); CRegKey keyVersion; if (keyVersion.Open(keyNS, szVersion, KEY_READ) == ERROR_SUCCESS) { CRegKey keyMain; if (keyMain.Open(keyVersion, _T("Main"), KEY_READ) == ERROR_SUCCESS) { DWORD nPluginsDir = sizeof(szPluginsDir) / sizeof(szPluginsDir[0]); keyMain.QueryValue(szPluginsDir, _T("Plugins Directory"), &nPluginsDir); keyMain.Close(); } keyVersion.Close(); } keyNS.Close(); } if (szPluginsDir[0]) { CreatePluginListFrom(szPluginsDir); } } // Try and obtain a path to the plugins in Internet Explorer if (ulFlags & PLUGINS_FROM_IE) { TCHAR szPluginsDir[_MAX_PATH]; memset(szPluginsDir, 0, sizeof(szPluginsDir)); CRegKey keyIE; const TCHAR *kIEKey = _T("Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\IEXPLORE.EXE"); if (keyIE.Open(HKEY_LOCAL_MACHINE, kIEKey, KEY_READ) == ERROR_SUCCESS) { DWORD nPluginsDir = sizeof(szPluginsDir) / sizeof(szPluginsDir[0]); keyIE.QueryValue(szPluginsDir, _T("Path"), &nPluginsDir); TCHAR *szSemiColon = _tcschr(szPluginsDir, _TCHAR(';')); if (szSemiColon) { *szSemiColon = _TCHAR('\0'); } ULONG nLen = _tcslen(szPluginsDir); if (nLen > 0 && szPluginsDir[nLen - 1] == _TCHAR('\\')) { szPluginsDir[nLen - 1] = _TCHAR('\0'); } _tcscat(szPluginsDir, _T("\\Plugins")); keyIE.Close(); } if (szPluginsDir[0]) { CreatePluginListFrom(szPluginsDir); } } return S_OK; } HRESULT nsPluginHostWnd::CreatePluginListFrom(const TCHAR *szPluginsDir) { HANDLE hFind; WIN32_FIND_DATA finddata; // Change to the plugin directory TCHAR szCurrentDir[MAX_PATH + 1]; GetCurrentDirectory(sizeof(szCurrentDir) / sizeof(szCurrentDir[0]), szCurrentDir); SetCurrentDirectory(szPluginsDir); // Search for files matching the "np*dll" pattern hFind = FindFirstFile(_T("np*dll"), &finddata); if (hFind != INVALID_HANDLE_VALUE) { do { PluginInfo *pInfo = new PluginInfo; if (!pInfo) { CleanupPluginList(); SetCurrentDirectory(szCurrentDir); return E_OUTOFMEMORY; } if (SUCCEEDED(GetPluginInfo(finddata.cFileName, pInfo))) { pInfo->szPluginName = _tcsdup(finddata.cFileName); pInfo->szPluginPath = _tcsdup(szPluginsDir); m_Plugins.AppendElement(pInfo); } else { ATLTRACE(_T("Error: Cannot plugin info for \"%s\".\n"), finddata.cFileName); delete pInfo; } } while (FindNextFile(hFind, &finddata)); FindClose(hFind); } SetCurrentDirectory(szCurrentDir); return S_OK; } HRESULT nsPluginHostWnd::CleanupPluginList() { // Free the memory used by the plugin info list for (unsigned long i = 0; i < m_Plugins.Count(); i++) { PluginInfo *pI = m_Plugins[i]; if (pI->szMIMEType) free(pI->szMIMEType); if (pI->szPluginName) free(pI->szPluginName); if (pI->szPluginPath) free(pI->szPluginPath); free(pI); } m_Plugins.Empty(); return S_OK; } HRESULT nsPluginHostWnd::GetPluginInfo(const TCHAR *pszPluginPath, PluginInfo *pInfo) { // Get the version info from the plugin USES_CONVERSION; DWORD nVersionInfoSize; DWORD nZero = 0; void *pVersionInfo = NULL; nVersionInfoSize = GetFileVersionInfoSize((TCHAR *)pszPluginPath, &nZero); if (nVersionInfoSize) { pVersionInfo = malloc(nVersionInfoSize); } if (!pVersionInfo) { return E_OUTOFMEMORY; } GetFileVersionInfo((TCHAR *)pszPluginPath, NULL, nVersionInfoSize, pVersionInfo); // Extract the MIMEType info TCHAR *szValue = NULL; UINT nValueLength = 0; if (!VerQueryValue(pVersionInfo, _T("\\StringFileInfo\\040904E4\\MIMEType"), (void **) &szValue, &nValueLength)) { return E_FAIL; } if (pInfo) { pInfo->szMIMEType = _tcsdup(szValue); } free(pVersionInfo); return S_OK; } HRESULT nsPluginHostWnd::FindPluginPathByContentType(const TCHAR *pszContentType, TCHAR **ppszPluginPath) { *ppszPluginPath = NULL; if (pszContentType == NULL) { return E_FAIL; } // Search the list of plugins for one that will handle the content type TCHAR szPluginPath[_MAX_PATH + 1]; unsigned long nContentType = _tcslen(pszContentType); for (unsigned long i = 0; i < m_Plugins.Count(); i++) { PluginInfo *pI = m_Plugins[i]; if (pI->szMIMEType) { TCHAR *pszMIMEType = pI->szMIMEType; do { if (_tcsncmp(pszContentType, pszMIMEType, nContentType) == 0) { // Found a match _tmakepath(szPluginPath, NULL, pI->szPluginPath, pI->szPluginName, NULL); *ppszPluginPath = _tcsdup(szPluginPath); return S_OK; } // Check the other types the plugin handles pszMIMEType = _tcschr(pszMIMEType, TCHAR('|')); if (pszMIMEType) { pszMIMEType++; } } while (pszMIMEType && *pszMIMEType); } } return E_FAIL; } HRESULT nsPluginHostWnd::LoadPlugin(const TCHAR *szPluginPath) { ATLASSERT(m_pLoadedPlugin == NULL); if (m_pLoadedPlugin) { return E_UNEXPECTED; } // TODO critical section // Test if the plugin has already been loaded for (unsigned long i = 0; i < m_LoadedPlugins.Count(); i++) { if (_tcscmp(m_LoadedPlugins[i]->szFullPath, szPluginPath) == 0) { m_pLoadedPlugin = m_LoadedPlugins[i]; memcpy(&m_NPPFuncs, &m_pLoadedPlugin->NPPFuncs, sizeof(m_NPPFuncs)); m_pLoadedPlugin->nRefCount++; return S_OK; } } // Plugin library is being loaded for the first time so initialise it // and store an entry in the loaded plugins array. HINSTANCE hInstance = LoadLibrary(szPluginPath); if (!hInstance) { return E_FAIL; } m_pLoadedPlugin = new LoadedPluginInfo; if (!m_pLoadedPlugin) { ATLASSERT(m_pLoadedPlugin); return E_OUTOFMEMORY; } // Get the plugin function entry points NP_GETENTRYPOINTS pfnGetEntryPoints = (NP_GETENTRYPOINTS) GetProcAddress(hInstance, "NP_GetEntryPoints"); if (pfnGetEntryPoints) { pfnGetEntryPoints(&m_NPPFuncs); } // Tell the plugin to initialize itself NP_PLUGININIT pfnInitialize = (NP_PLUGININIT) GetProcAddress(hInstance, "NP_Initialize"); if (!pfnInitialize) { pfnInitialize = (NP_PLUGININIT) GetProcAddress(hInstance, "NP_PluginInit"); } if (pfnInitialize) { pfnInitialize(&g_NPNFuncs); } // Create a new entry for the plugin m_pLoadedPlugin->szFullPath = _tcsdup(szPluginPath); m_pLoadedPlugin->nRefCount = 1; m_pLoadedPlugin->hInstance = hInstance; memcpy(&m_pLoadedPlugin->NPPFuncs, &m_NPPFuncs, sizeof(m_NPPFuncs)); // Add it to the array m_LoadedPlugins.AppendElement(m_pLoadedPlugin); return S_OK; } HRESULT nsPluginHostWnd::UnloadPlugin() { if (!m_pLoadedPlugin) { return E_FAIL; } // TODO critical section ATLASSERT(m_pLoadedPlugin->nRefCount > 0); if (m_pLoadedPlugin->nRefCount == 1) { NP_PLUGINSHUTDOWN pfnShutdown = (NP_PLUGINSHUTDOWN) GetProcAddress( m_pLoadedPlugin->hInstance, "NP_Shutdown"); if (pfnShutdown) { pfnShutdown(); } FreeLibrary(m_pLoadedPlugin->hInstance); // Delete the entry from the array m_LoadedPlugins.RemoveElement(m_pLoadedPlugin); free(m_pLoadedPlugin->szFullPath); delete m_pLoadedPlugin; } else { m_pLoadedPlugin->nRefCount--; } m_pLoadedPlugin = NULL; return S_OK; } HRESULT nsPluginHostWnd::AddPluginParam(const char *szName, const char *szValue) { ATLASSERT(szName); ATLASSERT(szValue); if (!szName || !szValue) { return E_INVALIDARG; } // Skip params that already there for (unsigned long i = 0; i < m_nArgs; i++) { if (stricmp(szName, m_pszArgNames[i]) == 0) { return S_OK; } } // Add the value if (!m_pszArgNames) { ATLASSERT(!m_pszArgValues); m_nArgsMax = kArraySizeIncrement; m_pszArgNames = (char **) malloc(sizeof(char *) * m_nArgsMax); m_pszArgValues = (char **) malloc(sizeof(char *) * m_nArgsMax); } else if (m_nArgs == m_nArgsMax) { m_nArgsMax += kArraySizeIncrement; m_pszArgNames = (char **) realloc(m_pszArgNames, sizeof(char *) * m_nArgsMax); m_pszArgValues = (char **) realloc(m_pszArgValues, sizeof(char *) * m_nArgsMax); } if (!m_pszArgNames || !m_pszArgValues) { return E_OUTOFMEMORY; } m_pszArgNames[m_nArgs] = strdup(szName); m_pszArgValues[m_nArgs] = strdup(szValue); m_nArgs++; return S_OK; } HRESULT nsPluginHostWnd::CreatePluginInstance() { m_NPP.pdata = NULL; m_NPP.ndata = this; USES_CONVERSION; char *szContentType = strdup(OLE2A(m_bstrContentType.m_str)); // Create a child window to house the plugin RECT rc; GetClientRect(&rc); // m_wndPlugin.Create(m_hWnd, rc, NULL, WS_CHILD | WS_VISIBLE); // m_NPWindow.window = (void *) m_wndPlugin.m_hWnd; m_NPWindow.window = (void *) m_hWnd; m_NPWindow.type = NPWindowTypeWindow; if (m_NPPFuncs.newp) { // Create the arguments to be fed into the plugin if (m_bstrSource.m_str) { AddPluginParam("SRC", OLE2A(m_bstrSource.m_str)); } if (m_bstrContentType.m_str) { AddPluginParam("TYPE", OLE2A(m_bstrContentType.m_str)); } if (m_bstrPluginsPage.m_str) { AddPluginParam("PLUGINSPAGE", OLE2A(m_bstrPluginsPage.m_str)); } char szTmp[50]; sprintf(szTmp, "%d", (int) (rc.right - rc.left)); AddPluginParam("WIDTH", szTmp); sprintf(szTmp, "%d", (int) (rc.bottom - rc.top)); AddPluginParam("HEIGHT", szTmp); NPSavedData *pSaved = NULL; // Create the plugin instance NPError npres = m_NPPFuncs.newp(szContentType, &m_NPP, NP_EMBED, (short) m_nArgs, m_pszArgNames, m_pszArgValues, pSaved); if (npres != NPERR_NO_ERROR) { return E_FAIL; } } m_bPluginIsAlive = true; SizeToFitPluginInstance(); return S_OK; } HRESULT nsPluginHostWnd::DestroyPluginInstance() { if (!m_bPluginIsAlive) { return S_OK; } // Destroy the plugin if (m_NPPFuncs.destroy) { NPSavedData *pSavedData = NULL; NPError npres = m_NPPFuncs.destroy(&m_NPP, &pSavedData); // TODO could store saved data instead of just deleting it. if (pSavedData && pSavedData->buf) { NPN_MemFree(pSavedData->buf); } } // Destroy the arguments if (m_pszArgNames) { for (unsigned long i = 0; i < m_nArgs; i++) { free(m_pszArgNames[i]); } free(m_pszArgNames); m_pszArgNames = NULL; } if (m_pszArgValues) { for (unsigned long i = 0; i < m_nArgs; i++) { free(m_pszArgValues[i]); } free(m_pszArgValues); m_pszArgValues = NULL; } //m_wndPlugin.DestroyWindow(); m_bPluginIsAlive = false; return S_OK; } HRESULT nsPluginHostWnd::SizeToFitPluginInstance() { if (!m_bPluginIsAlive) { return S_OK; } // Resize the plugin to fit the window RECT rc; GetClientRect(&rc); //m_wndPlugin.SetWindowPos(HWND_TOP, // rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, // SWP_NOZORDER); m_NPWindow.x = 0; m_NPWindow.y = 0; m_NPWindow.width = rc.right - rc.left; m_NPWindow.height = rc.bottom - rc.top; m_NPWindow.clipRect.left = 0; m_NPWindow.clipRect.top = 0; m_NPWindow.clipRect.right = m_NPWindow.width; m_NPWindow.clipRect.bottom = m_NPWindow.height; if (m_NPPFuncs.setwindow) { NPError npres = m_NPPFuncs.setwindow(&m_NPP, &m_NPWindow); } return S_OK; } HRESULT nsPluginHostWnd::OpenURLStream(const TCHAR *szURL, void *pNotifyData, const void *pPostData, unsigned long nPostDataLength) { nsURLDataCallback::OpenURL(this, szURL, pNotifyData, pPostData, nPostDataLength); return S_OK; }