|
|
|
@@ -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 <windows.h>
|
|
|
|
#include <windowsx.h>
|
|
|
|
#include <olectl.h>
|
|
|
|
#include <objsafe.h>
|
|
|
|
#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 <var::identifier> 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
|