diff --git a/extras/browser plugins/How to build a browser plugin.txt b/extras/browser plugins/How to build a browser plugin.txt index 2fb1e5335c..85e02072e3 100644 --- a/extras/browser plugins/How to build a browser plugin.txt +++ b/extras/browser plugins/How to build a browser plugin.txt @@ -53,3 +53,17 @@ Building a Windows NPAPI plugin in Visual Studio - Note that the "browser plugins/wrapper/npapi" folder contains a copy of some NPAPI header files. If you're building a closed-source project, please check the licensing details in these files to make sure you're not breaking any Mozilla licensing restictions. + + +Building a Windows ActiveX control for Internet Explorer +-------------------------------------------------------- + +- This is actually quite easy, because the same DLL that functions as an NPAPI plugin can + also be used as an ActiveX control. +- Just create a windows NPAPI plugin as described above, but add the juce_ActiveX_GlueCode.cpp + file to the project. +- In your BrowserPluginCharacteristics.h file, the JuceBrowserPlugin_ActiveXCLSID setting needs + to be given a unique GUID for your plugin. +- Because the plugin is a COM object, it doesn't matter where the DLL lives, but it needs to + be registered in the normal COM way, with regsvr32.exe. Note that on Vista, this command + needs to be run with administrator permissions for it to be able to write to the registry. diff --git a/extras/browser plugins/demo/build/npapi_mac/English.lproj/InfoPlist.strings b/extras/browser plugins/demo/build/mac/English.lproj/InfoPlist.strings similarity index 100% rename from extras/browser plugins/demo/build/npapi_mac/English.lproj/InfoPlist.strings rename to extras/browser plugins/demo/build/mac/English.lproj/InfoPlist.strings diff --git a/extras/browser plugins/demo/build/npapi_mac/Info.plist b/extras/browser plugins/demo/build/mac/Info.plist similarity index 100% rename from extras/browser plugins/demo/build/npapi_mac/Info.plist rename to extras/browser plugins/demo/build/mac/Info.plist diff --git a/extras/browser plugins/demo/build/npapi_mac/JuceBrowserPluginDemo.xcodeproj/TemplateIcon.tiff b/extras/browser plugins/demo/build/mac/JuceBrowserPluginDemo.xcodeproj/TemplateIcon.tiff similarity index 100% rename from extras/browser plugins/demo/build/npapi_mac/JuceBrowserPluginDemo.xcodeproj/TemplateIcon.tiff rename to extras/browser plugins/demo/build/mac/JuceBrowserPluginDemo.xcodeproj/TemplateIcon.tiff diff --git a/extras/browser plugins/demo/build/npapi_mac/JuceBrowserPluginDemo.xcodeproj/project.pbxproj b/extras/browser plugins/demo/build/mac/JuceBrowserPluginDemo.xcodeproj/project.pbxproj similarity index 100% rename from extras/browser plugins/demo/build/npapi_mac/JuceBrowserPluginDemo.xcodeproj/project.pbxproj rename to extras/browser plugins/demo/build/mac/JuceBrowserPluginDemo.xcodeproj/project.pbxproj diff --git a/extras/browser plugins/demo/build/npapi_win/JuceBrowserPluginDemo.sln b/extras/browser plugins/demo/build/npapi_win/JuceBrowserPluginDemo.sln deleted file mode 100644 index c05fe8a99e..0000000000 --- a/extras/browser plugins/demo/build/npapi_win/JuceBrowserPluginDemo.sln +++ /dev/null @@ -1,20 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual C++ Express 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JuceBrowserPluginDemo", "JuceBrowserPluginDemo.vcproj", "{865C6463-5BC7-4F36-8667-FF9221C32797}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {865C6463-5BC7-4F36-8667-FF9221C32797}.Debug|Win32.ActiveCfg = Debug|Win32 - {865C6463-5BC7-4F36-8667-FF9221C32797}.Debug|Win32.Build.0 = Debug|Win32 - {865C6463-5BC7-4F36-8667-FF9221C32797}.Release|Win32.ActiveCfg = Release|Win32 - {865C6463-5BC7-4F36-8667-FF9221C32797}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/extras/browser plugins/demo/build/npapi_win/JuceBrowserPluginDemo.vcproj b/extras/browser plugins/demo/build/npapi_win/JuceBrowserPluginDemo.vcproj deleted file mode 100644 index 80ab4ca13f..0000000000 --- a/extras/browser plugins/demo/build/npapi_win/JuceBrowserPluginDemo.vcproj +++ /dev/null @@ -1,216 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/extras/browser plugins/demo/src/BrowserPluginCharacteristics.h b/extras/browser plugins/demo/src/BrowserPluginCharacteristics.h index 1ef6f0399c..d0e9547399 100644 --- a/extras/browser plugins/demo/src/BrowserPluginCharacteristics.h +++ b/extras/browser plugins/demo/src/BrowserPluginCharacteristics.h @@ -35,3 +35,8 @@ can open. If you don't need to use it, just use a made-up name here. */ #define JuceBrowserPlugin_FileSuffix ".jucedemo" + +/** If you're building an activeX version, you'll need to create a unique GUID for + your plugin. Use a tool like uuidgen.exe to create this. +*/ +#define JuceBrowserPlugin_ActiveXCLSID "F683B990-3ADF-11DE-BDFE-F9CB55D89593" diff --git a/extras/browser plugins/demo/src/JuceBrowserPluginDemo.cpp b/extras/browser plugins/demo/src/JuceBrowserPluginDemo.cpp index 8b128d97d3..72edf2dcea 100644 --- a/extras/browser plugins/demo/src/JuceBrowserPluginDemo.cpp +++ b/extras/browser plugins/demo/src/JuceBrowserPluginDemo.cpp @@ -120,7 +120,7 @@ public: if (numParams > 0) owner->textBox->setText (owner->textBox->getText() + "\n" + params[0].toString()); - return var(); + return "text was printed ok!"; } const var popUpMessageBox (const var* params, int numParams) diff --git a/extras/browser plugins/demo/test.html b/extras/browser plugins/demo/test.html index e652d7539a..e478fb9ec1 100644 --- a/extras/browser plugins/demo/test.html +++ b/extras/browser plugins/demo/test.html @@ -15,7 +15,8 @@ function getPlugin() function showAMessage() { - getPlugin().printText ("This is a message sent from the website's javascript..."); + var response = getPlugin().printText ("This is a message sent from the website's javascript..."); + printmessage (response); } function popUpMessageBox() @@ -40,7 +41,14 @@ function sendCallbackObjectToPlugin() - + + + +
diff --git a/extras/browser plugins/wrapper/juce_ActiveX_GlueCode.cpp b/extras/browser plugins/wrapper/juce_ActiveX_GlueCode.cpp new file mode 100644 index 0000000000..77ea8485b5 --- /dev/null +++ b/extras/browser plugins/wrapper/juce_ActiveX_GlueCode.cpp @@ -0,0 +1,926 @@ +/* + ============================================================================== + + This file is part of the JUCE library - "Jules' Utility Class Extensions" + Copyright 2004-7 by Raw Material Software ltd. + + ------------------------------------------------------------------------------ + + JUCE can be redistributed and/or modified under the terms of the + GNU General Public License, as published by the Free Software Foundation; + either version 2 of the License, or (at your option) any later version. + + JUCE is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with JUCE; if not, visit www.gnu.org/licenses or write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + ------------------------------------------------------------------------------ + + If you'd like to release a closed-source product which uses JUCE, commercial + licenses are also available: visit www.rawmaterialsoftware.com/juce for + more information. + + ============================================================================== +*/ + +//============================================================================== +/* + This file contains all the gubbins to create an ActiveX browser plugin that + wraps your BrowserPluginComponent object. + +*/ +//============================================================================== +#if _MSC_VER + +//============================================================================== +#include +#include +#include +#include +#pragma warning (disable:4584) + +#include "../../../juce_amalgamated.h" +#include "juce_BrowserPluginComponent.h" +#include "juce_IncludeBrowserPluginInfo.h" + +#ifndef JuceBrowserPlugin_ActiveXCLSID +#error "For an activeX plugin, you need to define JuceBrowserPlugin_ActiveXCLSID in your BrowserPluginCharacteristics.h file!" +#endif + +//============================================================================== +#if JUCE_MAC && JUCE_DEBUG && 0 +static void log (const String& s) +{ + FILE* f = fopen ("/Users/jules/Desktop/log.txt", "a+"); + fprintf (f, (const char*) s); + fprintf (f, "\n"); + fflush (f); + fclose (f); +} +#else +#define log(a) DBG(a) +#endif + +// Cunning trick used to add functions to export list without messing about with .def files. +#define EXPORTED_FUNCTION comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__) + +//============================================================================== +static void juceVarToVariant (const var& v, VARIANT& dest); +static const var variantTojuceVar (const VARIANT& v); + +#if JUCE_DEBUG + static int numDOWID = 0, numJuceSO = 0; +#endif + +//============================================================================== +// Takes care of the logic in invoking var methods from IDispatch callbacks. +class IDispatchHelper +{ +public: + IDispatchHelper() {} + ~IDispatchHelper() {} + + var::identifier getId (int hash) const + { + for (int i = knownIdentifiers.size(); --i >= 0;) + if (knownIdentifiers.getUnchecked(i)->hashCode == hash) + return *knownIdentifiers.getUnchecked(i); + + return var::identifier (String::empty); + } + + var::identifier getId (const String& name) + { + for (int i = knownIdentifiers.size(); --i >= 0;) + if (knownIdentifiers.getUnchecked(i)->name == name) + return *knownIdentifiers.getUnchecked(i); + + const var::identifier v (name); + knownIdentifiers.add (new var::identifier (v)); + return v; + } + + HRESULT doGetIDsOfNames (LPOLESTR* rgszNames, UINT cNames, DISPID* rgDispId) + { + for (unsigned int i = 0; i < cNames; ++i) + { + var::identifier id (getId (rgszNames[i])); + rgDispId[i] = (DISPID) id.hashCode; + } + + return S_OK; + } + + HRESULT doInvoke (const var& v, + DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, + VARIANT* pVarResult, EXCEPINFO* pExcepInfo, UINT* puArgErr) + { + const var::identifier memberId (getId ((int) dispIdMember)); + + if (memberId.name.isEmpty() || v.getObject() == 0) + return DISP_E_MEMBERNOTFOUND; + + if ((wFlags & DISPATCH_METHOD) != 0) + { + if (! v.getObject()->hasMethod (memberId)) + return DISP_E_MEMBERNOTFOUND; + + const int numArgs = pDispParams == 0 ? 0 : pDispParams->cArgs; + var result; + + if (numArgs == 0) + { + result = v.call (memberId); + } + else + { + var* args = (var*) juce_calloc (sizeof (var) * numArgs); + for (int j = 0; j < numArgs; ++j) + args[j] = variantTojuceVar (pDispParams->rgvarg[j]); + + result = v.invoke (memberId, args, numArgs); + + for (int j = 0; j < numArgs; ++j) + args[j] = var(); + + juce_free (args); + } + + if (pVarResult != 0) + juceVarToVariant (result, *pVarResult); + + return S_OK; + } + else if ((wFlags & DISPATCH_PROPERTYGET) != 0) + { + if (! v.getObject()->hasProperty (memberId)) + return DISP_E_MEMBERNOTFOUND; + + if (pVarResult != 0) + { + juceVarToVariant (v.getObject()->getProperty (memberId), *pVarResult); + return S_OK; + } + } + else if ((wFlags & DISPATCH_PROPERTYPUT) != 0) + { + if (pDispParams != 0 && pDispParams->cArgs > 0) + { + v.getObject()->setProperty (memberId, variantTojuceVar (pDispParams->rgvarg[0])); + return S_OK; + } + } + + return DISP_E_MEMBERNOTFOUND; + } + +private: + OwnedArray knownIdentifiers; + + IDispatchHelper (const IDispatchHelper&); + const IDispatchHelper& operator= (const IDispatchHelper&); +}; + +//============================================================================== +// Makes a var look like an IDispatch +class IDispatchWrappingDynamicObject : public IDispatch +{ +public: + IDispatchWrappingDynamicObject (const var& object_) + : object (object_), + refCount (0) + { + DBG ("num Juce wrapper objs: " + String (++numJuceSO)); + } + + virtual ~IDispatchWrappingDynamicObject() + { + DBG ("num Juce wrapper objs: " + String (--numJuceSO)); + } + + HRESULT __stdcall QueryInterface (REFIID id, void __RPC_FAR* __RPC_FAR* result) + { + if (id == IID_IUnknown) { AddRef(); *result = (IUnknown*) this; return S_OK; } + else if (id == IID_IDispatch) { AddRef(); *result = (IDispatch*) this; return S_OK; } + + *result = 0; + return E_NOINTERFACE; + } + + ULONG __stdcall AddRef() { return ++refCount; } + ULONG __stdcall Release() { const int r = --refCount; if (r == 0) delete this; return r; } + + HRESULT __stdcall GetTypeInfoCount (UINT*) { return E_NOTIMPL; } + HRESULT __stdcall GetTypeInfo (UINT, LCID, ITypeInfo**) { return E_NOTIMPL; } + + HRESULT __stdcall GetIDsOfNames (REFIID riid, LPOLESTR* rgszNames, UINT cNames, + LCID lcid, DISPID* rgDispId) + { + return iDispatchHelper.doGetIDsOfNames (rgszNames, cNames, rgDispId); + } + + HRESULT __stdcall Invoke (DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, + DISPPARAMS* pDispParams, VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, UINT* puArgErr) + { + return iDispatchHelper.doInvoke (object, dispIdMember, riid, lcid, wFlags, pDispParams, + pVarResult, pExcepInfo, puArgErr); + } + +private: + //============================================================================== + var object; + int refCount; + IDispatchHelper iDispatchHelper; +}; + + +//============================================================================== +// Makes an IDispatch look like a var +class DynamicObjectWrappingIDispatch : public DynamicObject +{ + IDispatch* const source; + +public: + DynamicObjectWrappingIDispatch (IDispatch* const source_) + : source (source_) + { + source->AddRef(); + DBG ("num IDispatch wrapper objs: " + String (++numDOWID)); + } + + ~DynamicObjectWrappingIDispatch() + { + source->Release(); + DBG ("num IDispatch wrapper objs: " + String (--numDOWID)); + } + + const var getProperty (const var::identifier& propertyName) const + { + LPCOLESTR name = (LPCOLESTR) propertyName.name; + DISPID id = 0; + if (source->GetIDsOfNames (IID_NULL, (LPOLESTR*)&name, 1, 0, &id) == S_OK) + { + EXCEPINFO excepInfo; + DISPPARAMS params; + zerostruct (params); + UINT argError; + VARIANT result; + zerostruct (result); + + if (source->Invoke (id, IID_NULL, 0, DISPATCH_PROPERTYGET, + ¶ms, &result, &excepInfo, &argError) == S_OK) + { + var v (variantTojuceVar (result)); + VariantClear (&result); + return v; + } + } + + return var(); + } + + bool hasProperty (const var::identifier& propertyName) const + { + LPCOLESTR name = (LPCOLESTR) propertyName.name; + DISPID id = 0; + return source->GetIDsOfNames (IID_NULL, (LPOLESTR*)&name, 1, 0, &id) == S_OK; + } + + void setProperty (const var::identifier& propertyName, const var& newValue) + { + LPCOLESTR name = (LPCOLESTR) propertyName.name; + DISPID id = 0; + if (source->GetIDsOfNames (IID_NULL, (LPOLESTR*)&name, 1, 0, &id) == S_OK) + { + VARIANT param; + zerostruct (param); + juceVarToVariant (newValue, param); + + DISPPARAMS dispParams; + zerostruct (dispParams); + dispParams.cArgs = 1; + dispParams.rgvarg = ¶m; + EXCEPINFO excepInfo; + zerostruct (excepInfo); + + VARIANT result; + zerostruct (result); + UINT argError = 0; + + if (source->Invoke (id, IID_NULL, 0, DISPATCH_PROPERTYPUT, + &dispParams, &result, &excepInfo, &argError) == S_OK) + { + VariantClear (&result); + } + + VariantClear (¶m); + } + } + + void removeProperty (const var::identifier& propertyName) + { + setProperty (propertyName, var()); + } + + bool hasMethod (const var::identifier& methodName) const + { + LPCOLESTR name = (LPCOLESTR) methodName.name; + DISPID id = 0; + return source->GetIDsOfNames (IID_NULL, (LPOLESTR*)&name, 1, 0, &id) == S_OK; + } + + const var invokeMethod (const var::identifier& methodName, + const var* parameters, + int numParameters) + { + var returnValue; + LPCOLESTR name = (LPCOLESTR) methodName.name; + DISPID id = 0; + if (source->GetIDsOfNames (IID_NULL, (LPOLESTR*)&name, 1, 0, &id) == S_OK) + { + VARIANT* params = (VARIANT*) juce_calloc (sizeof (VARIANT) * (numParameters + 1)); + + for (int i = 0; i < numParameters; ++i) + juceVarToVariant (parameters[i], params[i]); + + DISPPARAMS dispParams; + zerostruct (dispParams); + dispParams.cArgs = numParameters; + dispParams.rgvarg = params; + + EXCEPINFO excepInfo; + zerostruct (excepInfo); + + VARIANT result; + zerostruct (result); + UINT argError = 0; + + if (source->Invoke (id, IID_NULL, 0, DISPATCH_METHOD, + &dispParams, &result, &excepInfo, &argError) == S_OK) + { + returnValue = variantTojuceVar (result); + VariantClear (&result); + } + + juce_free (params); + } + + return returnValue; + } +}; + + +//============================================================================== +void juceVarToVariant (const var& v, VARIANT& dest) +{ + if (v.isVoid()) + { + dest.vt = VT_EMPTY; + } + else if (v.isInt()) + { + dest.vt = VT_INT; + dest.intVal = (int) v; + } + else if (v.isBool()) + { + dest.vt = VT_BOOL; + dest.boolVal = (int) v; + } + else if (v.isDouble()) + { + dest.vt = VT_R8; + dest.dblVal = (double) v; + } + else if (v.isString()) + { + dest.vt = VT_BSTR; + dest.bstrVal = SysAllocString (v.toString()); + } + else if (v.isObject()) + { + dest.vt = VT_DISPATCH; + dest.pdispVal = new IDispatchWrappingDynamicObject (v); + } + else if (v.isMethod()) + { + dest.vt = VT_EMPTY; + } +} + +const var variantTojuceVar (const VARIANT& v) +{ + if ((v.vt & VT_ARRAY) != 0) + { + //xxx + } + else + { + switch (v.vt & ~VT_BYREF) + { + case VT_VOID: + case VT_EMPTY: return var(); + case VT_I1: return var ((int) v.cVal); + case VT_I2: return var ((int) v.iVal); + case VT_I4: return var ((int) v.lVal); + case VT_I8: return var (String (v.llVal)); + case VT_UI1: return var ((int) v.bVal); + case VT_UI2: return var ((int) v.uiVal); + case VT_UI4: return var ((int) v.ulVal); + case VT_UI8: return var (String (v.ullVal)); + case VT_INT: return var ((int) v.intVal); + case VT_UINT: return var ((int) v.uintVal); + case VT_R4: return var ((double) v.fltVal); + case VT_R8: return var ((double) v.dblVal); + case VT_BSTR: return var (v.bstrVal); + case VT_BOOL: return var (v.boolVal ? true : false); + case VT_DISPATCH: return var (new DynamicObjectWrappingIDispatch (v.pdispVal)); + default: + break; + } + } + + return var(); +} + +//============================================================================== +// This acts as the embedded HWND +class AXBrowserPluginHolderComponent : public Component +{ +public: + //============================================================================== + AXBrowserPluginHolderComponent() + : child (0), + parentHWND (0) + { + setOpaque (true); + setWantsKeyboardFocus (false); + + addAndMakeVisible (child = createBrowserPlugin()); + jassert (child != 0); // You have to create one of these! + } + + ~AXBrowserPluginHolderComponent() + { + setWindow (0); + deleteAndZero (child); + } + + //============================================================================== + void paint (Graphics& g) + { + if (child == 0 || ! child->isOpaque()) + g.fillAll (Colours::white); + } + + void resized() + { + if (child != 0) + child->setBounds (0, 0, getWidth(), getHeight()); + } + + const var getObject() { return child->getJavascriptObject(); } + + void setWindow (IOleInPlaceSite* site) + { + HWND newHWND = 0; + + if (site != 0) + site->GetWindow (&newHWND); + + //log ("setWindow: " + String ((int) newHWND)); + if (parentHWND != newHWND) + { + removeFromDesktop(); + setVisible (false); + + parentHWND = newHWND; + + if (parentHWND != 0) + { + addToDesktop (0); + + HWND ourHWND = (HWND) getWindowHandle(); + SetParent (ourHWND, parentHWND); + DWORD val = GetWindowLong (ourHWND, GWL_STYLE); + val = (val & ~WS_POPUP) | WS_CHILD; + SetWindowLong (ourHWND, GWL_STYLE, val); + + setVisible (true); + } + } + + if (site != 0) + site->OnInPlaceActivate(); + } + +private: + //============================================================================== + BrowserPluginComponent* child; + HWND parentHWND; +}; + +//============================================================================== +class JuceActiveXObject : public IUnknown, + public IDispatch, + public IObjectWithSite, + public IObjectSafety, + public IOleInPlaceObject +{ +public: + JuceActiveXObject() + : refCount (0) + { + log ("JuceActiveXObject"); + site = 0; + holderComp = 0; + } + + ~JuceActiveXObject() + { + deleteAndZero (holderComp); + log ("~JuceActiveXObject"); + } + + HRESULT __stdcall QueryInterface (REFIID id, void __RPC_FAR* __RPC_FAR* result) + { + if (id == IID_IUnknown) { AddRef(); *result = (IUnknown*) this; return S_OK; } + else if (id == IID_IDispatch) { AddRef(); *result = (IDispatch*) this; return S_OK; } + else if (id == IID_IObjectWithSite) { AddRef(); *result = (IObjectWithSite*) this; return S_OK; } + else if (id == IID_IObjectSafety) { AddRef(); *result = (IObjectSafety*) this; return S_OK; } + else if (id == IID_IOleInPlaceObject) { AddRef(); *result = (IOleInPlaceObject*) this; return S_OK; } + else if (id == IID_IOleWindow) { AddRef(); *result = (IOleWindow*) (IOleInPlaceObject*) this; return S_OK; } + + *result = 0; + return E_NOINTERFACE; + } + + ULONG __stdcall AddRef() { return ++refCount; } + ULONG __stdcall Release() { const int r = --refCount; if (r == 0) delete this; return r; } + + HRESULT __stdcall GetTypeInfoCount (UINT* pctinfo) { return E_NOTIMPL; } + HRESULT __stdcall GetTypeInfo (UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { return E_NOTIMPL; } + + HRESULT __stdcall GetIDsOfNames (REFIID riid, LPOLESTR* rgszNames, UINT cNames, + LCID lcid, DISPID* rgDispId) + { + return iDispatchHelper.doGetIDsOfNames (rgszNames, cNames, rgDispId); + } + + HRESULT __stdcall Invoke (DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, + DISPPARAMS* pDispParams, VARIANT* pVarResult, + EXCEPINFO* pExcepInfo, UINT* puArgErr) + { + if (holderComp == 0) + return DISP_E_MEMBERNOTFOUND; + + return iDispatchHelper.doInvoke (holderComp->getObject(), + dispIdMember, riid, lcid, wFlags, pDispParams, + pVarResult, pExcepInfo, puArgErr); + } + + HRESULT __stdcall SetSite (IUnknown* newSite) + { + if (newSite != site) + { + if (site != 0) + site->Release(); + + site = newSite; + + if (site != 0) + { + site->AddRef(); + + IOleInPlaceSite* inPlaceSite = 0; + site->QueryInterface (IID_IOleInPlaceSite, (void**) &inPlaceSite); + + if (inPlaceSite != 0) + { + if (holderComp == 0) + holderComp = new AXBrowserPluginHolderComponent(); + + holderComp->setWindow (inPlaceSite); + + inPlaceSite->Release(); + } + else + { + deleteAndZero (holderComp); + } + } + else + { + deleteAndZero (holderComp); + } + } + + return S_OK; + } + + HRESULT __stdcall GetSite (REFIID riid, void **ppvSite) + { + *ppvSite = site; + return S_OK; + } + + //============================================================================== + HRESULT __stdcall SetObjectRects (LPCRECT r, LPCRECT c) + { + if (holderComp != 0) + holderComp->setBounds (r->left, r->top, r->right - r->left, r->bottom - r->top); + + return S_OK; + } + + HRESULT __stdcall GetWindow (__RPC__deref_out_opt HWND* phwnd) + { + if (holderComp == 0) + return E_NOTIMPL; + + *phwnd = (HWND) holderComp->getWindowHandle(); + return S_OK; + } + + //============================================================================== + HRESULT __stdcall ContextSensitiveHelp (BOOL fEnterMode) { return E_NOTIMPL; } + HRESULT __stdcall InPlaceDeactivate() { return E_NOTIMPL; } + HRESULT __stdcall UIDeactivate() { return E_NOTIMPL; } + HRESULT __stdcall ReactivateAndUndo() { return E_NOTIMPL; } + + //============================================================================== + HRESULT __stdcall GetInterfaceSafetyOptions (REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions) + { + *pdwSupportedOptions = *pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA; + return S_OK; + } + + HRESULT __stdcall SetInterfaceSafetyOptions (REFIID, DWORD, DWORD) { return S_OK; } + +private: + IUnknown* site; + int refCount; + AXBrowserPluginHolderComponent* holderComp; + IDispatchHelper iDispatchHelper; + + JuceActiveXObject (const JuceActiveXObject&); + const JuceActiveXObject& operator= (const JuceActiveXObject&); +}; + +//============================================================================== +class JuceActiveXObjectFactory : public IUnknown, + public IClassFactory +{ +public: + JuceActiveXObjectFactory() : refCount (0) {} + ~JuceActiveXObjectFactory() {} + + HRESULT __stdcall QueryInterface (REFIID id, void __RPC_FAR* __RPC_FAR* result) + { + if (id == IID_IUnknown) { AddRef(); *result = (IUnknown*) this; return S_OK; } + else if (id == IID_IClassFactory) { AddRef(); *result = (IClassFactory*) this; return S_OK; } + + *result = 0; + return E_NOINTERFACE; + } + + ULONG __stdcall AddRef() { return ++refCount; } + ULONG __stdcall Release() { const int r = --refCount; if (r == 0) delete this; return r; } + + HRESULT __stdcall CreateInstance (IUnknown* pUnkOuter, REFIID riid, void** ppvObject) + { + *ppvObject = 0; + + if (pUnkOuter != 0 && riid != IID_IUnknown) + return CLASS_E_NOAGGREGATION; + + JuceActiveXObject* ax = new JuceActiveXObject(); + return ax->QueryInterface (riid, ppvObject); + } + + HRESULT __stdcall LockServer (BOOL /*fLock*/) { return S_OK; } + +private: + int refCount; + + JuceActiveXObjectFactory (const JuceActiveXObjectFactory&); + const JuceActiveXObjectFactory& operator= (const JuceActiveXObjectFactory&); +}; + +//============================================================================== +extern String browserVersionDesc; + +static const String getExePath() +{ + TCHAR moduleFile [2048]; + moduleFile[0] = 0; + GetModuleFileName (0, moduleFile, 2048); + return moduleFile; +} + +static const String getExeVersion (const String& exeFileName, const String& fieldName) +{ + String resultString; + DWORD pointlessWin32Variable; + DWORD size = GetFileVersionInfoSize (exeFileName, &pointlessWin32Variable); + + if (size > 0) + { + void* const exeInfo = juce_calloc (size); + + if (GetFileVersionInfo (exeFileName, 0, size, exeInfo)) + { + TCHAR* result = 0; + unsigned int resultLen = 0; + + // try the 1200 codepage (Unicode) + String queryStr ("\\StringFileInfo\\040904B0\\" + fieldName); + + if (! VerQueryValue (exeInfo, queryStr, (void**) &result, &resultLen)) + { + // try the 1252 codepage (Windows Multilingual) + queryStr = "\\StringFileInfo\\040904E4\\" + fieldName; + VerQueryValue (exeInfo, queryStr, (void**) &result, &resultLen); + } + + resultString = String (result, resultLen); + } + + juce_free (exeInfo); + } + + return resultString; +} + +//============================================================================== +extern "C" BOOL WINAPI DllMain (HANDLE instance, DWORD reason, LPVOID) +{ + #pragma EXPORTED_FUNCTION + + static int numPluginInstances = 0; + + switch (reason) + { + case DLL_PROCESS_ATTACH: + log ("DLL_PROCESS_ATTACH"); + + if (numPluginInstances++ == 0) + { + log ("initialiseJuce_GUI()"); + initialiseJuce_GUI(); + + browserVersionDesc = "Internet Explorer " + getExeVersion (getExePath(), "FileVersion"); + } + + PlatformUtilities::setCurrentModuleInstanceHandle (instance); + break; + + case DLL_PROCESS_DETACH: + log ("DLL_PROCESS_DETACH"); + + if (--numPluginInstances == 0) + { + log ("shutdownJuce_GUI()"); + browserVersionDesc = String::empty; + shutdownJuce_GUI(); + } + + break; + + default: + break; + } + + return TRUE; +} + +static const String CLSIDToJuceString (REFCLSID clsid) +{ + LPWSTR s = 0; + StringFromIID (clsid, &s); + + if (s == 0) + return String::empty; + + const String result (s); + LPMALLOC malloc; + CoGetMalloc (1, &malloc); + if (malloc != 0) + { + malloc->Free (s); + malloc->Release(); + } + + return result.removeCharacters (T("{}")).trim(); +} + +STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + #pragma EXPORTED_FUNCTION + + *ppv = 0; + + if (CLSIDToJuceString (rclsid) == String (JuceBrowserPlugin_ActiveXCLSID)) + { + JuceActiveXObjectFactory* afx = new JuceActiveXObjectFactory(); + if (afx->QueryInterface (riid, ppv) == S_OK) + return S_OK; + + delete afx; + } + + return CLASS_E_CLASSNOTAVAILABLE; +} + +STDAPI DllCanUnloadNow() +{ + #pragma EXPORTED_FUNCTION + return S_OK; +} + +//============================================================================== +static const String makeLegalRegistryName (const String& s) +{ + return s.retainCharacters (T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.")); +} + +static HRESULT doRegistration (const bool unregister) +{ + const String company (makeLegalRegistryName (JuceBrowserPlugin_Company)); + const String plugin (makeLegalRegistryName (JuceBrowserPlugin_Name)); + const String clsID ("{" + String (JuceBrowserPlugin_ActiveXCLSID) + "}"); + const String root ("HKEY_CLASSES_ROOT\\"); + const String companyDotPlugin (company + "." + plugin); + const String companyDotPluginCur (companyDotPlugin + ".1"); + const String clsIDRoot (root + "CLSID\\" + clsID + "\\"); + const String dllPath (File::getSpecialLocation (File::currentApplicationFile).getFullPathName()); + + StringPairArray settings; + settings.set (root + companyDotPluginCur + "\\", JuceBrowserPlugin_Name); + settings.set (root + companyDotPluginCur + "\\CLSID\\", clsID); + settings.set (root + companyDotPlugin + "\\", JuceBrowserPlugin_Name); + settings.set (root + companyDotPlugin + "\\CLSID\\", clsID); + settings.set (root + companyDotPlugin + "\\CurVer\\", companyDotPluginCur); + settings.set (clsIDRoot, JuceBrowserPlugin_Name); + settings.set (clsIDRoot + "Implemented Categories\\{7DD95801-9882-11CF-9FA9-00AA006C42C4}\\", String::empty); + settings.set (clsIDRoot + "Implemented Categories\\{7DD95802-9882-11CF-9FA9-00AA006C42C4}\\", String::empty); + settings.set (clsIDRoot + "ProgID\\", companyDotPluginCur); + settings.set (clsIDRoot + "VersionIndependentProgID\\", companyDotPlugin); + settings.set (clsIDRoot + "Programmable\\", String::empty); + settings.set (clsIDRoot + "InProcServer32\\", dllPath); + settings.set (clsIDRoot + "InProcServer32\\ThreadingModel", "Apartment"); + settings.set (clsIDRoot + "Control\\", String::empty); + settings.set (clsIDRoot + "Insertable\\", String::empty); + settings.set (clsIDRoot + "ToolboxBitmap32\\", dllPath + ", 101"); + settings.set (clsIDRoot + "TypeLib\\", ""); + settings.set (clsIDRoot + "Version\\", JuceBrowserPlugin_Version); + + if (unregister) + { + for (int i = 0; i < settings.getAllKeys().size(); ++i) + PlatformUtilities::deleteRegistryValue (settings.getAllKeys()[i]); + + PlatformUtilities::deleteRegistryKey (root + companyDotPluginCur); + PlatformUtilities::deleteRegistryKey (root + companyDotPlugin); + PlatformUtilities::deleteRegistryKey (clsIDRoot); + + if (PlatformUtilities::registryValueExists (clsIDRoot + "InProcServer32")) + return SELFREG_E_CLASS; + } + else + { + PlatformUtilities::deleteRegistryKey (clsIDRoot); + + for (int i = 0; i < settings.getAllKeys().size(); ++i) + PlatformUtilities::setRegistryValue (settings.getAllKeys()[i], + settings [settings.getAllKeys()[i]]); + + // check whether the registration actually worked - if not, we probably don't have + // enough privileges to write to the registry.. + if (PlatformUtilities::getRegistryValue (clsIDRoot + "InProcServer32\\") != dllPath) + return SELFREG_E_CLASS; + } + + return S_OK; +} + +STDAPI DllRegisterServer() +{ + #pragma EXPORTED_FUNCTION + return doRegistration (false); +} + +STDAPI DllUnregisterServer() +{ + #pragma EXPORTED_FUNCTION + return doRegistration (true); +} + +#endif diff --git a/extras/browser plugins/wrapper/juce_NPAPI_GlueCode.cpp b/extras/browser plugins/wrapper/juce_NPAPI_GlueCode.cpp index bd70245257..86a6bd5bb9 100644 --- a/extras/browser plugins/wrapper/juce_NPAPI_GlueCode.cpp +++ b/extras/browser plugins/wrapper/juce_NPAPI_GlueCode.cpp @@ -106,6 +106,7 @@ extern "C" //============================================================================== static NPNetscapeFuncs browser; +String browserVersionDesc; //============================================================================== NPError NP_GetValue (void* future, NPPVariable variable, void* value) @@ -924,8 +925,8 @@ NPError NPP_New (NPMIMEType pluginType, NPP npp, ::uint16 mode, ::int16 argc, ch if (numPluginInstances++ == 0) { - initialiseJuce_GUI(); log ("initialiseJuce_GUI()"); + initialiseJuce_GUI(); } currentlyInitialisingNPP = npp; @@ -950,8 +951,9 @@ NPError NPP_Destroy (NPP npp, NPSavedData** save) if (--numPluginInstances == 0) { - shutdownJuce_GUI(); log ("shutdownJuce_GUI()"); + shutdownJuce_GUI(); + browserVersionDesc = String::empty; } } @@ -1100,15 +1102,17 @@ BrowserPluginComponent::BrowserPluginComponent() BrowserPluginComponent::~BrowserPluginComponent() { } + const String BrowserPluginComponent::getBrowserVersion() const { - String s; - - if (getInstance (this) != 0) - s << browser.uagent (getInstance (this)); - else - s << "Netscape Plugin V" << (int) ((browser.version >> 8) & 0xff) - << "." << (int) (browser.version & 0xff); + if (browserVersionDesc.isEmpty()) + { + if (getInstance (this) != 0) + browserVersionDesc << browser.uagent (getInstance (this)); + else + browserVersionDesc << "Netscape Plugin V" << (int) ((browser.version >> 8) & 0xff) + << "." << (int) (browser.version & 0xff); + } - return s; + return browserVersionDesc; }