Back to index

lightning-sunbird  0.9+nobinonly
LegacyPlugin.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Adam Lock <adamlock@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 #include "stdafx.h"
00039 
00040 #include "jni.h"
00041 #include "npapi.h"
00042 
00043 #include "nsISupports.h"
00044 
00045 #ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
00046 #include "XPConnect.h"
00047 #endif
00048 
00049 #ifdef MOZ_ACTIVEX_PLUGIN_LIVECONNECT
00050 #include "LiveConnect.h"
00051 #endif
00052 
00053 #include "LegacyPlugin.h"
00054 
00055 #ifdef XPC_IDISPATCH_SUPPORT
00056 #include "nsCOMPtr.h"
00057 #include "nsString.h"
00058 #include "nsIDocument.h"
00059 #include "nsIDOMElement.h"
00060 #include "nsIDOMDocument.h"
00061 #include "nsIDOMWindow.h"
00062 #include "nsIScriptGlobalObject.h"
00063 #include "nsIScriptContext.h"
00064 #include "nsIURI.h"
00065 #include "nsIJSContextStack.h"
00066 #include "jsapi.h"
00067 #include "jscntxt.h"
00068 #include "nsIScriptSecurityManager.h"
00069 #endif
00070 
00072 // These are constants to control certain default behaviours
00073 
00074 #ifndef MOZ_ACTIVEX_PLUGIN_XPCONNECT
00075 // Flag determines if controls should be created if they are not marked
00076 // safe for scripting.
00077 const BOOL kHostSafeControlsOnly = FALSE;
00078 // Flag determines if controls should be downloaded and installed if there is a
00079 // codebase specified
00080 const BOOL kDownloadControlsIfMissing = FALSE;
00081 #endif
00082 
00083 // Flag determines whether the plugin will complain to the user if a page
00084 // contains a control it cannot load
00085 const BOOL kDisplayErrorMessages = FALSE;
00086 
00088 // CInstallControlProgress
00089 
00090 class CInstallControlProgress :
00091     public CComObjectRootEx<CComSingleThreadModel>,
00092     public IBindStatusCallback,
00093     public IWindowForBindingUI
00094 {
00095 public:
00096     CInstallControlProgress()
00097     {
00098     }
00099 
00100     BOOL mBindingInProgress;
00101     HRESULT mResult;
00102     NPP mNPP;
00103 
00104 protected:
00105     virtual ~CInstallControlProgress()
00106     {
00107     }
00108 public:
00109 BEGIN_COM_MAP(CInstallControlProgress)
00110     COM_INTERFACE_ENTRY(IBindStatusCallback)
00111     COM_INTERFACE_ENTRY(IWindowForBindingUI)
00112 END_COM_MAP()
00113 
00114 // IBindStatusCallback
00115     HRESULT STDMETHODCALLTYPE OnStartBinding(DWORD dwReserved, 
00116                                             IBinding __RPC_FAR *pib)
00117     {
00118         return S_OK;
00119     }
00120 
00121     HRESULT STDMETHODCALLTYPE GetPriority(LONG __RPC_FAR *pnPriority)
00122     {
00123         return S_OK;
00124     }
00125         
00126     HRESULT STDMETHODCALLTYPE OnLowResource(DWORD reserved)
00127     {
00128         return S_OK;
00129     }
00130         
00131     HRESULT STDMETHODCALLTYPE OnProgress(ULONG ulProgress, 
00132                                          ULONG ulProgressMax, 
00133                                          ULONG ulStatusCode, 
00134                                          LPCWSTR szStatusText)
00135     {
00136         switch (ulStatusCode)
00137         {
00138         case BINDSTATUS_BEGINDOWNLOADDATA:
00139         case BINDSTATUS_DOWNLOADINGDATA:
00140         case BINDSTATUS_ENDDOWNLOADDATA:
00141             {
00142                 char szMsg[100];
00143                 _snprintf(szMsg, sizeof(szMsg) - 1, "Downloading control (%lu of %lu)", ulProgress, ulProgressMax);
00144                 szMsg[sizeof(szMsg) - 1] = '\0';
00145                 NPN_Status(mNPP, szMsg);
00146             }
00147             break;
00148         case BINDSTATUS_FINDINGRESOURCE:
00149         case BINDSTATUS_CONNECTING:
00150         case BINDSTATUS_REDIRECTING:
00151         case BINDSTATUS_BEGINDOWNLOADCOMPONENTS:
00152         case BINDSTATUS_INSTALLINGCOMPONENTS:
00153         case BINDSTATUS_ENDDOWNLOADCOMPONENTS:
00154         case BINDSTATUS_USINGCACHEDCOPY:
00155         case BINDSTATUS_SENDINGREQUEST:
00156         case BINDSTATUS_CLASSIDAVAILABLE:
00157         case BINDSTATUS_MIMETYPEAVAILABLE:
00158         case BINDSTATUS_CACHEFILENAMEAVAILABLE:
00159         case BINDSTATUS_BEGINSYNCOPERATION:
00160         case BINDSTATUS_ENDSYNCOPERATION:
00161         case BINDSTATUS_BEGINUPLOADDATA:
00162         case BINDSTATUS_UPLOADINGDATA:
00163         case BINDSTATUS_ENDUPLOADDATA:
00164         case BINDSTATUS_PROTOCOLCLASSID:
00165         case BINDSTATUS_ENCODING:
00166         case BINDSTATUS_CLASSINSTALLLOCATION:
00167         case BINDSTATUS_DECODING:
00168         case BINDSTATUS_LOADINGMIMEHANDLER:
00169         default:
00170             /* do nothing */
00171             break;
00172         }
00173         return S_OK;
00174     }
00175 
00176     HRESULT STDMETHODCALLTYPE OnStopBinding(HRESULT hresult, LPCWSTR szError)
00177     {
00178         mBindingInProgress = FALSE;
00179         mResult = hresult;
00180         NPN_Status(mNPP, "");
00181         return S_OK;
00182     }
00183         
00184     HRESULT STDMETHODCALLTYPE GetBindInfo(DWORD __RPC_FAR *pgrfBINDF, 
00185                                                         BINDINFO __RPC_FAR *pbindInfo)
00186     {
00187         *pgrfBINDF = BINDF_ASYNCHRONOUS | BINDF_ASYNCSTORAGE |
00188                     BINDF_GETNEWESTVERSION | BINDF_NOWRITECACHE;
00189         pbindInfo->cbSize = sizeof(BINDINFO);
00190         pbindInfo->szExtraInfo = NULL;
00191         memset(&pbindInfo->stgmedData, 0, sizeof(STGMEDIUM));
00192         pbindInfo->grfBindInfoF = 0;
00193         pbindInfo->dwBindVerb = 0;
00194         pbindInfo->szCustomVerb = NULL;
00195         return S_OK;
00196     }
00197         
00198     HRESULT STDMETHODCALLTYPE OnDataAvailable(DWORD grfBSCF, 
00199                                               DWORD dwSize, 
00200                                               FORMATETC __RPC_FAR *pformatetc, 
00201                                               STGMEDIUM __RPC_FAR *pstgmed)
00202     {
00203         return E_NOTIMPL;
00204     }
00205       
00206     HRESULT STDMETHODCALLTYPE OnObjectAvailable(REFIID riid, 
00207                                                 IUnknown __RPC_FAR *punk)
00208     {
00209         return S_OK;
00210     }
00211 
00212 // IWindowForBindingUI
00213     virtual HRESULT STDMETHODCALLTYPE GetWindow(
00214         /* [in] */ REFGUID rguidReason,
00215         /* [out] */ HWND *phwnd)
00216     {
00217         HWND hwnd = NULL;
00218         NPN_GetValue(mNPP, NPNVnetscapeWindow, &hwnd);
00219         *phwnd = hwnd;
00220         return S_OK;
00221     }
00222 };
00223 
00225 
00226 
00227 // NPP_Initialize
00228 //
00229 //    Initialize the plugin library. Your DLL global initialization
00230 //    should be here
00231 //
00232 NPError NPP_Initialize(void)
00233 {
00234     ATLTRACE(_T("NPP_Initialize()\n"));
00235     _Module.Lock();
00236     return NPERR_NO_ERROR;
00237 }
00238 
00239 
00240 // NPP_Shutdown
00241 //
00242 //    shutdown the plugin library. Revert initializition
00243 //
00244 void NPP_Shutdown(void)
00245 {
00246     ATLTRACE(_T("NPP_Shutdown()\n"));
00247 #ifdef MOZ_ACTIVEX_PLUGIN_LIVECONNECT
00248     liveconnect_Shutdown();
00249 #endif
00250     _Module.Unlock();
00251 }
00252 
00253 
00254 // NPP_GetJavaClass
00255 //
00256 //    Return the Java class representing this plugin
00257 //
00258 jref NPP_GetJavaClass(void)
00259 {
00260     ATLTRACE(_T("NPP_GetJavaClass()\n"));
00261 #ifdef MOZ_ACTIVEX_PLUGIN_LIVECONNECT
00262     return liveconnect_GetJavaClass();
00263 #endif
00264     return NULL;
00265 }
00266 
00267 #define MIME_OLEOBJECT1   "application/x-oleobject"
00268 #define MIME_OLEOBJECT2   "application/oleobject"
00269 
00270 enum MozAxPluginErrors
00271 {
00272     MozAxErrorControlIsNotSafeForScripting,
00273     MozAxErrorCouldNotCreateControl,
00274 };
00275 
00276 static void
00277 ShowError(MozAxPluginErrors errorCode, const CLSID &clsid)
00278 {
00279     if (!kDisplayErrorMessages)
00280         return;
00281 
00282     const TCHAR *szMsg = NULL;
00283     const unsigned long kBufSize = 256;
00284     TCHAR szBuffer[kBufSize];
00285 
00286     // TODO errors are hardcoded for now
00287     switch (errorCode)
00288     {
00289     case MozAxErrorControlIsNotSafeForScripting:
00290         {
00291             USES_CONVERSION;
00292             LPOLESTR szClsid;
00293             StringFromCLSID(clsid, &szClsid);
00294             _sntprintf(szBuffer, kBufSize - 1,
00295                 _T("Could not create the control %s because it is not marked safe for scripting."), OLE2T(szClsid));
00296             CoTaskMemFree(szClsid);
00297             szMsg = szBuffer;
00298         }
00299         break;
00300     case MozAxErrorCouldNotCreateControl:
00301         {
00302             USES_CONVERSION;
00303             LPOLESTR szClsid;
00304             StringFromCLSID(clsid, &szClsid);
00305             _sntprintf(szBuffer, kBufSize - 1,
00306                 _T("Could not create the control %s. Check that it has been installed on your computer "
00307                    "and that this page correctly references it."), OLE2T(szClsid));
00308             CoTaskMemFree(szClsid);
00309             szMsg = szBuffer;
00310         }
00311         break;
00312     }
00313     szBuffer[kBufSize - 1] = TCHAR('\0');
00314     if (szMsg)
00315         MessageBox(NULL, szMsg, _T("ActiveX Error"), MB_OK | MB_ICONWARNING);
00316 }
00317 
00318 #if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
00319 
00320 static nsresult
00321 CreatePrincipal(nsIURI * origin,
00322                 nsIPrincipal ** outPrincipal)
00323 {
00324     nsresult rv;
00325     nsCOMPtr<nsIScriptSecurityManager> secMan(
00326         do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
00327     if (NS_FAILED(rv)) return rv;
00328 
00329     return secMan->GetCodebasePrincipal(origin, outPrincipal);
00330 }
00331 
00332 /***************************************************************************/
00333 // A class to put on the stack to manage JS contexts when we are entering JS.
00334 // This pushes and pops the given context
00335 // with the nsThreadJSContextStack service as this object goes into and out
00336 // of scope. It is optimized to not push/pop the cx if it is already on top
00337 // of the stack. We need to push the JSContext when we enter JS because the
00338 // JS security manager looks on the context stack for permissions information.
00339 
00340 class MozAxAutoPushJSContext
00341 {
00342 public:
00343     MozAxAutoPushJSContext(JSContext *cx, nsIURI * aURI);
00344 
00345     ~MozAxAutoPushJSContext();
00346 
00347     nsresult ResultOfPush() { return mPushResult; };
00348 
00349 private:
00350     nsCOMPtr<nsIJSContextStack> mContextStack;
00351     JSContext*                  mContext;
00352     JSStackFrame                mFrame;
00353     nsresult                    mPushResult;
00354 };
00355 
00356 
00357 MozAxAutoPushJSContext::MozAxAutoPushJSContext(JSContext *cx,
00358                                                nsIURI * aURI)
00359                                      : mContext(cx), mPushResult(NS_OK)
00360 {
00361     nsCOMPtr<nsIJSContextStack> contextStack =
00362         do_GetService("@mozilla.org/js/xpc/ContextStack;1");
00363 
00364     JSContext* currentCX;
00365     if(contextStack &&
00366        // Don't push if the current context is already on the stack.
00367        (NS_FAILED(contextStack->Peek(&currentCX)) ||
00368         cx != currentCX) )
00369     {
00370         if (NS_SUCCEEDED(contextStack->Push(cx)))
00371         {
00372             // Leave the reference in mContextStack to
00373             // indicate that we need to pop it in our dtor.
00374             mContextStack.swap(contextStack);
00375         }
00376     }
00377 
00378     memset(&mFrame, 0, sizeof(mFrame));
00379 
00380     // See if there are any scripts on the stack.
00381     // If not, we need to add a dummy frame with a principal.
00382     PRBool hasScript = PR_FALSE;
00383     JSStackFrame* tempFP = cx->fp;
00384     while (tempFP)
00385     {
00386         if (tempFP->script)
00387         {
00388             hasScript = PR_TRUE;
00389             break;
00390         }
00391         tempFP = tempFP->down;
00392     };
00393 
00394     if (!hasScript)
00395     {
00396         nsCOMPtr<nsIPrincipal> principal;
00397         mPushResult = CreatePrincipal(aURI, getter_AddRefs(principal));
00398 
00399         if (NS_SUCCEEDED(mPushResult))
00400         {
00401             JSPrincipals* jsprinc;
00402             principal->GetJSPrincipals(cx, &jsprinc);
00403 
00404             mFrame.script = JS_CompileScriptForPrincipals(cx, JS_GetGlobalObject(cx),
00405                                                           jsprinc, "", 0, "", 1);
00406             JSPRINCIPALS_DROP(cx, jsprinc);
00407 
00408             if (mFrame.script)
00409             {
00410                 mFrame.down = cx->fp;
00411                 cx->fp = &mFrame;
00412             }
00413             else
00414                 mPushResult = NS_ERROR_OUT_OF_MEMORY;
00415         }
00416     }
00417 }
00418 
00419 MozAxAutoPushJSContext::~MozAxAutoPushJSContext()
00420 {
00421     if (mContextStack)
00422         mContextStack->Pop(nsnull);
00423 
00424     if (mFrame.script)
00425         mContext->fp = mFrame.down;
00426 
00427 }
00428 
00429 
00430 static JSContext*
00431 GetPluginsContext(PluginInstanceData *pData)
00432 {
00433     nsCOMPtr<nsIDOMWindow> window;
00434     NPN_GetValue(pData->pPluginInstance, NPNVDOMWindow, 
00435                  NS_STATIC_CAST(nsIDOMWindow **, getter_AddRefs(window)));
00436 
00437     nsCOMPtr<nsIScriptGlobalObject> globalObject(do_QueryInterface(window));
00438     if (!globalObject)
00439         return nsnull;
00440 
00441     nsIScriptContext *scriptContext = globalObject->GetContext();
00442 
00443     if (!scriptContext)
00444         return nsnull;
00445 
00446     return NS_REINTERPRET_CAST(JSContext*, scriptContext->GetNativeContext());
00447 }
00448 
00449 #endif
00450 
00451 static BOOL
00452 WillHandleCLSID(const CLSID &clsid, PluginInstanceData *pData)
00453 {
00454 #if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
00455     // Ensure the control is safe for scripting
00456     nsCOMPtr<nsIDispatchSupport> dispSupport = do_GetService(NS_IDISPATCH_SUPPORT_CONTRACTID);
00457     if (!dispSupport)
00458         return FALSE;
00459     JSContext * cx = GetPluginsContext(pData);
00460     if (!cx)
00461         return FALSE;
00462     nsCID cid;
00463     memcpy(&cid, &clsid, sizeof(nsCID));
00464     PRBool isSafe = PR_FALSE;
00465     PRBool classExists = PR_FALSE;
00466     nsCOMPtr<nsIURI> uri;
00467     MozAxPlugin::GetCurrentLocation(pData->pPluginInstance, getter_AddRefs(uri));
00468     MozAxAutoPushJSContext autoContext(cx, uri);
00469     dispSupport->IsClassSafeToHost(cx, cid, PR_TRUE, &classExists, &isSafe);
00470     if (classExists && !isSafe)
00471         return FALSE;
00472     return TRUE;
00473 #else
00474     if (::IsEqualCLSID(clsid, CLSID_NULL))
00475     {
00476         return FALSE;
00477     }
00478 
00479     // Check the Internet Explorer list of vulnerable controls
00480     CRegKey keyExplorer;
00481     if (keyExplorer.Open(HKEY_LOCAL_MACHINE,
00482         _T("SOFTWARE\\Microsoft\\Internet Explorer\\ActiveX Compatibility"), KEY_READ) == ERROR_SUCCESS)
00483     {
00484         LPOLESTR szCLSID = NULL;
00485         ::StringFromCLSID(clsid, &szCLSID);
00486         if (szCLSID)
00487         {
00488             CRegKey keyCLSID;
00489             USES_CONVERSION;
00490             if (keyCLSID.Open(keyExplorer, W2T(szCLSID), KEY_READ) == ERROR_SUCCESS)
00491             {
00492                 DWORD dwType = REG_DWORD;
00493                 DWORD dwFlags = 0;
00494                 DWORD dwBufSize = sizeof(dwFlags);
00495                 if (::RegQueryValueEx(keyCLSID, _T("Compatibility Flags"),
00496                     NULL, &dwType, (LPBYTE) &dwFlags, &dwBufSize) == ERROR_SUCCESS)
00497                 {
00498                     // Flags for this reg key
00499                     const DWORD kKillBit = 0x00000400;
00500                     if (dwFlags & kKillBit)
00501                     {
00502                         ::CoTaskMemFree(szCLSID);
00503                         return FALSE;
00504                     }
00505                 }
00506             }
00507             ::CoTaskMemFree(szCLSID);
00508         }
00509     }
00510 
00511     // Check if the CLSID belongs to a list that the plugin does not support
00512     CRegKey keyDeny;
00513     if (keyDeny.Open(HKEY_LOCAL_MACHINE, kControlsToDenyKey, KEY_READ) == ERROR_SUCCESS)
00514     {
00515         // Enumerate CLSIDs looking for this one
00516         int i = 0;
00517         do {
00518             USES_CONVERSION;
00519             TCHAR szCLSID[64];
00520             const DWORD nLength = sizeof(szCLSID) / sizeof(szCLSID[0]);
00521             if (::RegEnumKey(keyDeny, i++, szCLSID, nLength) != ERROR_SUCCESS)
00522             {
00523                 break;
00524             }
00525             szCLSID[nLength - 1] = TCHAR('\0');
00526             CLSID clsidToCompare = GUID_NULL;
00527             if (SUCCEEDED(::CLSIDFromString(T2OLE(szCLSID), &clsidToCompare)) &&
00528                 ::IsEqualCLSID(clsid, clsidToCompare))
00529             {
00530                 return FALSE;
00531             }
00532         } while (1);
00533         keyDeny.Close();
00534     }
00535 
00536     // Check if the CLSID belongs to a list that the plugin only supports
00537     CRegKey keyAllow;
00538     if (keyAllow.Open(HKEY_LOCAL_MACHINE, kControlsToAllowKey, KEY_READ) == ERROR_SUCCESS)
00539     {
00540         // Enumerate CLSIDs looking for this one
00541         int i = 0;
00542         do {
00543             USES_CONVERSION;
00544             TCHAR szCLSID[64];
00545             const DWORD nLength = sizeof(szCLSID) / sizeof(szCLSID[0]);
00546             if (::RegEnumKey(keyAllow, i, szCLSID, nLength) != ERROR_SUCCESS)
00547             {
00548                 // An empty list means all controls are allowed.
00549                 return (i == 0) ? TRUE : FALSE;
00550             }
00551             ++i;
00552             szCLSID[nLength - 1] = TCHAR('\0');
00553             CLSID clsidToCompare = GUID_NULL;
00554             if (SUCCEEDED(::CLSIDFromString(T2OLE(szCLSID), &clsidToCompare)) &&
00555                 ::IsEqualCLSID(clsid, clsidToCompare))
00556             {
00557                 return TRUE;
00558             }
00559         } while (1);
00560     }
00561 
00562     return TRUE;
00563 #endif
00564 }
00565 
00566 static NPError
00567 CreateControl(const CLSID &clsid, PluginInstanceData *pData, PropertyList &pl, LPCOLESTR szCodebase)
00568 {
00569     // Make sure we got a CLSID we can handle
00570     if (!WillHandleCLSID(clsid, pData))
00571     {
00572         return NPERR_GENERIC_ERROR;
00573     }
00574 
00575     pData->clsid = clsid;
00576 
00577     // Set flags to specify if it is allowed to host safe or unsafe controls
00578     // and download them.
00579     PRBool hostSafeControlsOnly;
00580     PRBool downloadControlsIfMissing;
00581 #if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
00582     PRUint32 hostingFlags = MozAxPlugin::PrefGetHostingFlags();
00583     if (hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_SAFE_OBJECTS &&
00584         !(hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_ALL_OBJECTS))
00585     {
00586         hostSafeControlsOnly = TRUE;
00587     }
00588     else if (hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_HOST_ALL_OBJECTS)
00589     {
00590         hostSafeControlsOnly = FALSE;
00591     }
00592     else
00593     {
00594         // Plugin can host neither safe nor unsafe controls, so just return
00595         // without creating anything.
00596         return NPERR_GENERIC_ERROR;
00597     }
00598     if (hostingFlags & nsIActiveXSecurityPolicy::HOSTING_FLAGS_DOWNLOAD_CONTROLS)
00599     {
00600         downloadControlsIfMissing = PR_TRUE;
00601     }
00602     else
00603     {
00604         downloadControlsIfMissing = PR_FALSE;
00605     }
00606     // Ensure we can obtain the nsIDispatchSupport service
00607     nsCOMPtr<nsIDispatchSupport> dispSupport = do_GetService(NS_IDISPATCH_SUPPORT_CONTRACTID);
00608     if (!dispSupport)
00609     {
00610         return NPERR_GENERIC_ERROR;
00611     }
00612     // Now test if the CLSID is safe for scripting
00613     PRBool classIsMarkedSafeForScripting = PR_FALSE;
00614     if (hostSafeControlsOnly)
00615     {
00616         PRBool classExists = PR_FALSE;
00617         PRBool isClassSafeForScripting = PR_FALSE;
00618         nsCID cid;
00619         memcpy(&cid, &clsid, sizeof(cid));
00620         if (NS_SUCCEEDED(dispSupport->IsClassMarkedSafeForScripting(cid, &classExists, &isClassSafeForScripting)) &&
00621             classExists && isClassSafeForScripting)
00622         {
00623             classIsMarkedSafeForScripting = PR_TRUE;
00624         }
00625     }
00626 #else
00627     hostSafeControlsOnly = kHostSafeControlsOnly;
00628     downloadControlsIfMissing = kDownloadControlsIfMissing;
00629 #endif
00630 
00631     // Create the control site
00632     CControlSiteInstance *pSite = NULL;
00633     CControlSiteInstance::CreateInstance(&pSite);
00634     if (pSite == NULL)
00635     {
00636         return NPERR_GENERIC_ERROR;
00637     }
00638 
00639     pSite->m_bSupportWindowlessActivation = FALSE;
00640 #if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
00641     // We handle our own security further down
00642     pSite->SetSecurityPolicy(NULL);
00643     pSite->m_bSafeForScriptingObjectsOnly = FALSE;
00644 #else
00645     pSite->m_bSafeForScriptingObjectsOnly = hostSafeControlsOnly;
00646 #endif
00647 
00648     pSite->AddRef();
00649 
00650 #ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
00651     // Set up the service provider and container so the control can get hold
00652     // of the IE DOM and other interfaces
00653     CComPtr<IServiceProvider> sp;
00654     MozAxPlugin::GetServiceProvider(pData, &sp);
00655     if (sp)
00656         pSite->SetServiceProvider(sp);
00657     CComQIPtr<IOleContainer> container  = sp;
00658     if (container)
00659         pSite->SetContainer(container);
00660 #endif
00661 
00662     // TODO check the object is installed and at least as recent as
00663     //      that specified in szCodebase
00664 
00665     // Create the object
00666     HRESULT hr;
00667     if (!downloadControlsIfMissing || !szCodebase)
00668     {
00669         hr = pSite->Create(clsid, pl);
00670     }
00671     else if (szCodebase)
00672     {
00673         CComObject<CInstallControlProgress> *pProgress = NULL;
00674         CComPtr<IBindCtx> spBindCtx;
00675         CComPtr<IBindStatusCallback> spOldBSC;
00676         CComObject<CInstallControlProgress>::CreateInstance(&pProgress);
00677         pProgress->AddRef();
00678         CreateBindCtx(0, &spBindCtx);
00679         RegisterBindStatusCallback(spBindCtx, dynamic_cast<IBindStatusCallback *>(pProgress), &spOldBSC, 0);
00680 
00681         hr = pSite->Create(clsid, pl, szCodebase, spBindCtx);
00682         if (hr == MK_S_ASYNCHRONOUS)
00683         {
00684             pProgress->mNPP = pData->pPluginInstance;
00685             pProgress->mBindingInProgress = TRUE;
00686             pProgress->mResult = E_FAIL;
00687 
00688             // Spin around waiting for binding to complete
00689             HANDLE hFakeEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
00690             while (pProgress->mBindingInProgress)
00691             {
00692                 MSG msg;
00693                 // Process pending messages
00694                 while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
00695                 {
00696                     if (!::GetMessage(&msg, NULL, 0, 0))
00697                     {
00698                         pProgress->mBindingInProgress = FALSE;
00699                         break;
00700                     }
00701                     ::TranslateMessage(&msg);
00702                     ::DispatchMessage(&msg);
00703                 }
00704                 if (!pProgress->mBindingInProgress)
00705                     break;
00706                 // Sleep for a bit or the next msg to appear
00707                 ::MsgWaitForMultipleObjects(1, &hFakeEvent, FALSE, 500, QS_ALLEVENTS);
00708             }
00709             ::CloseHandle(hFakeEvent);
00710 
00711             hr = pProgress->mResult;
00712             if (SUCCEEDED(hr))
00713             {
00714                 hr = pSite->Create(clsid, pl);
00715             }
00716         }
00717         if (pProgress)
00718         {
00719             RevokeBindStatusCallback(spBindCtx, dynamic_cast<IBindStatusCallback *>(pProgress));
00720             pProgress->Release();
00721         }
00722     }
00723     if (FAILED(hr))
00724     {
00725         ShowError(MozAxErrorCouldNotCreateControl, clsid);
00726     }
00727 #if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
00728     if (SUCCEEDED(hr) && hostSafeControlsOnly && !classIsMarkedSafeForScripting)
00729     {
00730         CComPtr<IUnknown> cpUnk;
00731         pSite->GetControlUnknown(&cpUnk);
00732         nsIID iidDispatch;
00733         memcpy(&iidDispatch, &__uuidof(IDispatch), sizeof(nsIID));
00734         PRBool isObjectSafe = PR_FALSE;
00735         if (!cpUnk ||
00736             NS_FAILED(dispSupport->IsObjectSafeForScripting(
00737                 reinterpret_cast<void *>(cpUnk.p), iidDispatch, &isObjectSafe)) ||
00738             !isObjectSafe)
00739         {
00740             pSite->Detach();
00741             hr = E_FAIL;
00742             ShowError(MozAxErrorControlIsNotSafeForScripting, clsid);
00743             // DROP THROUGH
00744         }
00745     }
00746 #endif
00747 
00748     // Clean up if the control could not be created
00749     if (FAILED(hr))
00750     {
00751         pSite->Release();
00752         return NPERR_GENERIC_ERROR;
00753     }
00754     
00755 #if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
00756     // Hook up the event sink
00757     nsEventSinkInstance *pSink = NULL;
00758     nsEventSinkInstance::CreateInstance(&pSink);
00759     if (pSink)
00760     {
00761         pSink->AddRef();
00762         pSink->mPlugin = pData;
00763         CComPtr<IUnknown> control;
00764         pSite->GetControlUnknown(&control);
00765         pSink->SubscribeToEvents(control);
00766     }
00767     pData->pControlEventSink = pSink;
00768 #endif
00769     pData->nType = itControl;
00770     pData->pControlSite = pSite;
00771 
00772     return NPERR_NO_ERROR;
00773 }
00774 
00775 static NPError
00776 NewControl(const char *pluginType,
00777            PluginInstanceData *pData,
00778            uint16 mode,
00779            int16 argc,
00780            char *argn[],
00781            char *argv[])
00782 {
00783     // Read the parameters
00784     CLSID clsid = CLSID_NULL;
00785     CComBSTR codebase;
00786     PropertyList pl;
00787 
00788     if (strcmp(pluginType, MIME_OLEOBJECT1) != 0 &&
00789         strcmp(pluginType, MIME_OLEOBJECT2) != 0)
00790     {
00791         clsid = MozAxPlugin::GetCLSIDForType(pluginType);
00792     }
00793 
00794     for (int16 i = 0; i < argc; i++)
00795     {
00796         if (stricmp(argn[i], "CLSID") == 0 ||
00797             stricmp(argn[i], "CLASSID") == 0)
00798         {
00799             // Accept CLSIDs specified in various ways
00800             // e.g:
00801             //   "CLSID:C16DF970-D1BA-11d2-A252-000000000000"
00802             //   "C16DF970-D1BA-11d2-A252-000000000000"
00803             //   "{C16DF970-D1BA-11d2-A252-000000000000}"
00804             //
00805             // The first example is the proper way
00806 
00807             const int kCLSIDLen = 256;
00808             char szCLSID[kCLSIDLen];
00809             if (strlen(argv[i]) < sizeof(szCLSID))
00810             {
00811                 if (strnicmp(argv[i], "CLSID:", 6) == 0)
00812                 {
00813                     _snprintf(szCLSID, kCLSIDLen - 1, "{%s}", argv[i]+6);
00814                 }
00815                 else if(argv[i][0] != '{')
00816                 {
00817                     _snprintf(szCLSID, kCLSIDLen - 1, "{%s}", argv[i]);
00818                 }
00819                 else
00820                 {
00821                     strncpy(szCLSID, argv[i], kCLSIDLen - 1);
00822                 }
00823                 szCLSID[kCLSIDLen - 1] = '\0';
00824                 USES_CONVERSION;
00825                 CLSIDFromString(A2OLE(szCLSID), &clsid);
00826             }
00827         }
00828         else if (stricmp(argn[i], "CODEBASE") == 0)
00829         {
00830             codebase = argv[i];
00831 
00832 #ifdef XPC_IDISPATCH_SUPPORT
00833             // resolve relative URLs on CODEBASE
00834             if (argv[i])
00835             {
00836                 nsCOMPtr<nsIDOMElement> element;
00837                 NPN_GetValue(pData->pPluginInstance, NPNVDOMElement, 
00838                              NS_STATIC_CAST(nsIDOMElement **, getter_AddRefs(element)));
00839                 if (element)
00840                 {
00841                     nsCOMPtr<nsIDOMNode> tagAsNode (do_QueryInterface(element));
00842                     if (tagAsNode)
00843                     {
00844                         nsCOMPtr<nsIDOMDocument> DOMdocument;
00845                         tagAsNode->GetOwnerDocument(getter_AddRefs(DOMdocument));
00846                         // XXX nsIDocument is not frozen!!!
00847                         nsCOMPtr<nsIDocument> doc(do_QueryInterface(DOMdocument));
00848                         if (doc)
00849                         {
00850                             nsIURI *baseURI = doc->GetBaseURI();
00851                             if (baseURI)
00852                             {
00853                                 nsCAutoString newURL;
00854                                 if (NS_SUCCEEDED(baseURI->Resolve(nsDependentCString(argv[i]), newURL)))
00855                                 {
00856                                     codebase = newURL.get();
00857                                 }
00858                             }
00859                         }
00860                     }
00861                 }
00862             }
00863 #endif
00864 
00865         }
00866         else 
00867         {
00868             CComBSTR paramName;
00869             if (strnicmp(argn[i], "PARAM_", 6) == 0)
00870             {
00871                 paramName = argn[i] + 6;
00872             }
00873             else if (stricmp(argn[i], "PARAM") == 0)
00874             {
00875                 // The next argn and argv values after this symbol
00876                 // will be <param> tag names and values
00877                 continue;
00878             }
00879             else
00880             {
00881                 paramName = argn[i];
00882             }
00883 
00884             // Empty parameters are ignored
00885             if (!paramName.m_str || paramName.Length() == 0)
00886             {
00887                 continue;
00888             }
00889 
00890             USES_CONVERSION;
00891             CComBSTR paramValue(A2W(argv[i]));
00892 
00893             // Check for existing params with the same name
00894             BOOL bFound = FALSE;
00895             for (unsigned long j = 0; j < pl.GetSize(); j++)
00896             {
00897                 if (wcscmp(pl.GetNameOf(j), (BSTR) paramName) == 0)
00898                 {
00899                     bFound = TRUE;
00900                     break;
00901                 }
00902             }
00903             // If the parameter already exists, don't add it to the
00904             // list again.
00905             if (bFound)
00906             {
00907                 continue;
00908             }
00909 
00910             // Add named parameter to list
00911             CComVariant v(paramValue);
00912             pl.AddNamedProperty(paramName, v);
00913         }
00914     }
00915 
00916     return CreateControl(clsid, pData, pl, codebase.m_str);
00917 }
00918 
00919 
00920 // NPP_New
00921 //
00922 //    create a new plugin instance 
00923 //    handle any instance specific code initialization here
00924 //
00925 NPError NP_LOADDS NPP_New(NPMIMEType pluginType,
00926                 NPP instance,
00927                 uint16 mode,
00928                 int16 argc,
00929                 char* argn[],
00930                 char* argv[],
00931                 NPSavedData* saved)
00932 {
00933     ATLTRACE(_T("NPP_New()\n"));
00934 
00935     // trap duff args
00936     if (instance == NULL)
00937     {
00938         return NPERR_INVALID_INSTANCE_ERROR;
00939     }
00940 
00941     PluginInstanceData *pData = new PluginInstanceData;
00942     if (pData == NULL)
00943     {
00944         return NPERR_GENERIC_ERROR;
00945     }
00946     pData->pPluginInstance = instance;
00947     pData->szUrl = NULL;
00948     pData->szContentType = (pluginType) ? strdup(pluginType) : NULL;
00949 #ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
00950     pData->pScriptingPeer = NULL;
00951 #endif
00952 
00953     // Create a plugin according to the mime type
00954 #ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
00955     MozAxPlugin::AddRef();
00956 #endif
00957 
00958     NPError rv = NPERR_GENERIC_ERROR;
00959     /* if (strcmp(pluginType, MIME_OLEOBJECT1) == 0 ||
00960            strcmp(pluginType, MIME_OLEOBJECT2) == 0) */
00961     {
00962         rv = NewControl(pluginType, pData, mode, argc, argn, argv);
00963     }
00964 
00965     // Test if plugin creation has succeeded and cleanup if it hasn't
00966     if (rv != NPERR_NO_ERROR)
00967     {
00968         if (pData->szContentType)
00969             free(pData->szContentType);
00970         if (pData->szUrl)
00971             free(pData->szUrl);
00972         delete pData;
00973 #ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
00974         MozAxPlugin::Release();
00975 #endif
00976         return rv;
00977     }
00978 
00979     instance->pdata = pData;
00980 
00981     return NPERR_NO_ERROR;
00982 }
00983 
00984 
00985 // NPP_Destroy
00986 //
00987 //    Deletes a plug-in instance and releases all of its resources.
00988 //
00989 NPError NP_LOADDS
00990 NPP_Destroy(NPP instance, NPSavedData** save)
00991 {
00992     ATLTRACE(_T("NPP_Destroy()\n"));
00993 
00994     PluginInstanceData *pData = (PluginInstanceData *) instance->pdata;
00995     if (pData == NULL)
00996     {
00997         return NPERR_INVALID_INSTANCE_ERROR;
00998     }
00999 
01000     if (pData->nType == itControl)
01001     {
01002         // Destroy the site
01003         CControlSiteInstance *pSite = pData->pControlSite;
01004         if (pSite)
01005         {
01006             pSite->Detach();
01007             pSite->Release();
01008         }
01009 #if defined(MOZ_ACTIVEX_PLUGIN_XPCONNECT) && defined(XPC_IDISPATCH_SUPPORT)
01010         if (pData->pControlEventSink)
01011         {
01012             pData->pControlEventSink->UnsubscribeFromEvents();
01013             pData->pControlEventSink->Release();
01014         }
01015 #endif
01016 #ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
01017         if (pData->pScriptingPeer)
01018         {
01019             pData->pScriptingPeer->Release();
01020         }
01021 #endif
01022     }
01023     else if (pData->nType == itScript)
01024     {
01025         // TODO
01026     }
01027 
01028     if (pData->szUrl)
01029         free(pData->szUrl);
01030     if (pData->szContentType)
01031         free(pData->szContentType);
01032     delete pData;
01033 #ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
01034     MozAxPlugin::Release();
01035 #endif
01036 
01037     instance->pdata = 0;
01038 
01039     return NPERR_NO_ERROR;
01040 
01041 }
01042 
01043 
01044 // NPP_SetWindow
01045 //
01046 //    Associates a platform specific window handle with a plug-in instance.
01047 //        Called multiple times while, e.g., scrolling.  Can be called for three
01048 //        reasons:
01049 //
01050 //            1.  A new window has been created
01051 //            2.  A window has been moved or resized
01052 //            3.  A window has been destroyed
01053 //
01054 //    There is also the degenerate case;  that it was called spuriously, and
01055 //  the window handle and or coords may have or have not changed, or
01056 //  the window handle and or coords may be ZERO.  State information
01057 //  must be maintained by the plug-in to correctly handle the degenerate
01058 //  case.
01059 //
01060 NPError NP_LOADDS
01061 NPP_SetWindow(NPP instance, NPWindow* window)
01062 {
01063     ATLTRACE(_T("NPP_SetWindow()\n"));
01064 
01065     // Reject silly parameters
01066     if (!window)
01067     {
01068         return NPERR_GENERIC_ERROR;
01069     }
01070 
01071     PluginInstanceData *pData = (PluginInstanceData *) instance->pdata;
01072     if (pData == NULL)
01073     {
01074         return  NPERR_INVALID_INSTANCE_ERROR;
01075     }
01076 
01077     if (pData->nType == itControl)
01078     {
01079         CControlSiteInstance *pSite = pData->pControlSite;
01080         if (pSite == NULL)
01081         {
01082             return NPERR_GENERIC_ERROR;
01083         }
01084 
01085         HWND hwndParent = (HWND) window->window;
01086         if (hwndParent)
01087         {
01088             RECT rcPos;
01089             GetClientRect(hwndParent, &rcPos);
01090 
01091             if (pSite->GetParentWindow() == NULL)
01092             {
01093                 pSite->Attach(hwndParent, rcPos, NULL);
01094             }
01095             else
01096             {
01097                 pSite->SetPosition(rcPos);
01098             }
01099 
01100             // Ensure clipping on parent to keep child controls happy
01101             ::SetWindowLong(hwndParent, GWL_STYLE,
01102                 ::GetWindowLong(hwndParent, GWL_STYLE) | WS_CLIPCHILDREN);
01103         }
01104     }
01105 
01106     return NPERR_NO_ERROR;
01107 }
01108 
01109 
01110 // NPP_NewStream
01111 //
01112 //    Notifies the plugin of a new data stream.
01113 //  The data type of the stream (a MIME name) is provided.
01114 //  The stream object indicates whether it is seekable.
01115 //  The plugin specifies how it wants to handle the stream.
01116 //
01117 //  In this case, I set the streamtype to be NPAsFile.  This tells the Navigator
01118 //  that the plugin doesn't handle streaming and can only deal with the object as
01119 //  a complete disk file.  It will still call the write functions but it will also
01120 //  pass the filename of the cached file in a later NPE_StreamAsFile call when it
01121 //  is done transferring the file.
01122 //
01123 //  If a plugin handles the data in a streaming manner, it should set streamtype to
01124 //  NPNormal  (e.g. *streamtype = NPNormal)...the NPE_StreamAsFile function will
01125 //  never be called in this case
01126 //
01127 NPError NP_LOADDS
01128 NPP_NewStream(NPP instance,
01129               NPMIMEType type,
01130               NPStream *stream, 
01131               NPBool seekable,
01132               uint16 *stype)
01133 {
01134     ATLTRACE(_T("NPP_NewStream()\n"));
01135 
01136     if(!instance)
01137     {
01138         return NPERR_INVALID_INSTANCE_ERROR;
01139     }
01140 
01141     // save the plugin instance object in the stream instance
01142     stream->pdata = instance->pdata;
01143     *stype = NP_ASFILE;
01144     return NPERR_NO_ERROR;
01145 }
01146 
01147 
01148 // NPP_StreamAsFile
01149 //
01150 //    The stream is done transferring and here is a pointer to the file in the cache
01151 //    This function is only called if the streamtype was set to NPAsFile.
01152 //
01153 void NP_LOADDS
01154 NPP_StreamAsFile(NPP instance, NPStream *stream, const char* fname)
01155 {
01156     ATLTRACE(_T("NPP_StreamAsFile()\n"));
01157 
01158     if(fname == NULL || fname[0] == NULL)
01159     {
01160         return;
01161     }
01162 }
01163 
01164 
01165 //
01166 //        These next 2 functions are really only directly relevant 
01167 //        in a plug-in which handles the data in a streaming manner.  
01168 //        For a NPAsFile stream, they are still called but can safely 
01169 //        be ignored.
01170 //
01171 //        In a streaming plugin, all data handling would take place here...
01172 //
01174 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\.
01175 
01176 int32 STREAMBUFSIZE = 0X0FFFFFFF;   // we are reading from a file in NPAsFile mode
01177                                     // so we can take any size stream in our write
01178                                     // call (since we ignore it)
01179                                 
01180 
01181 // NPP_WriteReady
01182 //
01183 //    The number of bytes that a plug-in is willing to accept in a subsequent
01184 //    NPO_Write call.
01185 //
01186 int32 NP_LOADDS
01187 NPP_WriteReady(NPP instance, NPStream *stream)
01188 {
01189     return STREAMBUFSIZE;  
01190 }
01191 
01192 
01193 // NPP_Write
01194 //
01195 //    Provides len bytes of data.
01196 //
01197 int32 NP_LOADDS
01198 NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buffer)
01199 {   
01200     return len;
01201 }
01202 
01203 
01204 // NPP_DestroyStream
01205 //
01206 //    Closes a stream object.  
01207 //    reason indicates why the stream was closed.  Possible reasons are
01208 //    that it was complete, because there was some error, or because 
01209 //    the user aborted it.
01210 //
01211 NPError NP_LOADDS
01212 NPP_DestroyStream(NPP instance, NPStream *stream, NPError reason)
01213 {
01214     // because I am handling the stream as a file, I don't do anything here...
01215     // If I was streaming, I would know that I was done and do anything appropriate
01216     // to the end of the stream...   
01217     return NPERR_NO_ERROR;
01218 }
01219 
01220 
01221 // NPP_Print
01222 //
01223 //    Printing the plugin (to be continued...)
01224 //
01225 void NP_LOADDS
01226 NPP_Print(NPP instance, NPPrint* printInfo)
01227 {
01228     if(printInfo == NULL)   // trap invalid parm
01229     {
01230         return;
01231     }
01232 
01233 //    if (instance != NULL) {
01234 //        CPluginWindow* pluginData = (CPluginWindow*) instance->pdata;
01235 //        pluginData->Print(printInfo);
01236 //    }
01237 }
01238 
01239 /*******************************************************************************
01240 // NPP_URLNotify:
01241 // Notifies the instance of the completion of a URL request. 
01242 // 
01243 // NPP_URLNotify is called when Netscape completes a NPN_GetURLNotify or
01244 // NPN_PostURLNotify request, to inform the plug-in that the request,
01245 // identified by url, has completed for the reason specified by reason. The most
01246 // common reason code is NPRES_DONE, indicating simply that the request
01247 // completed normally. Other possible reason codes are NPRES_USER_BREAK,
01248 // indicating that the request was halted due to a user action (for example,
01249 // clicking the "Stop" button), and NPRES_NETWORK_ERR, indicating that the
01250 // request could not be completed (for example, because the URL could not be
01251 // found). The complete list of reason codes is found in npapi.h. 
01252 // 
01253 // The parameter notifyData is the same plug-in-private value passed as an
01254 // argument to the corresponding NPN_GetURLNotify or NPN_PostURLNotify
01255 // call, and can be used by your plug-in to uniquely identify the request. 
01256  ******************************************************************************/
01257 
01258 void
01259 NPP_URLNotify(NPP instance, const char* url, NPReason reason, void* notifyData)
01260 {
01261     PluginInstanceData *pData = (PluginInstanceData *) instance->pdata;
01262     if (pData)
01263     {
01264         if (pData->szUrl)
01265             free(pData->szUrl);
01266         pData->szUrl = strdup(url);
01267     }
01268 }
01269 
01270 NPError       NP_LOADDS
01271 NPP_GetValue(NPP instance, NPPVariable variable, void *value)
01272 {
01273     NPError rv = NPERR_GENERIC_ERROR;
01274 #ifdef MOZ_ACTIVEX_PLUGIN_XPCONNECT
01275     rv = MozAxPlugin::GetValue(instance, variable, value);
01276 #endif
01277     return rv;
01278 }
01279 
01280 NPError       NP_LOADDS
01281 NPP_SetValue(NPP instance, NPNVariable variable, void *value)
01282 {
01283     return NPERR_GENERIC_ERROR;
01284 }