From 0b046c94ac52b05983ac8cae7e2aef0bfec771b3 Mon Sep 17 00:00:00 2001
From: Jacek Caban <jacek@codeweavers.com>
Date: Thu, 2 Dec 2010 13:50:02 +0100
Subject: [PATCH] mshtml: Added ActiveX control creation implementation.

---
 dlls/mshtml/npplugin.c      | 183 +++++++++++++++++++++++++++++++++++-
 dlls/mshtml/nsiface.idl     |  75 +++++++++++++++
 dlls/mshtml/tests/activex.c |  12 ++-
 3 files changed, 264 insertions(+), 6 deletions(-)

diff --git a/dlls/mshtml/npplugin.c b/dlls/mshtml/npplugin.c
index bd3d64f81f3..5f21ce17951 100644
--- a/dlls/mshtml/npplugin.c
+++ b/dlls/mshtml/npplugin.c
@@ -92,11 +92,190 @@ typedef struct _NPPluginFuncs {
     NPP_LostFocusPtr lostfocus;
 } NPPluginFuncs;
 
+static nsIDOMElement *get_dom_element(NPP instance)
+{
+    nsISupports *instance_unk = (nsISupports*)instance->ndata;
+    nsIPluginInstance *plugin_instance;
+    nsIPluginInstanceOwner *owner;
+    nsIPluginTagInfo *tag_info;
+    nsIDOMElement *elem;
+    nsresult nsres;
+
+    nsres = nsISupports_QueryInterface(instance_unk, &IID_nsIPluginInstance, (void**)&plugin_instance);
+    if(NS_FAILED(nsres))
+        return NULL;
+
+    nsres = nsIPluginInstance_GetOwner(plugin_instance, &owner);
+    nsIPluginInstance_Release(instance_unk);
+    if(NS_FAILED(nsres) || !owner)
+        return NULL;
+
+    nsres = nsISupports_QueryInterface(owner, &IID_nsIPluginTagInfo, (void**)&tag_info);
+    nsISupports_Release(owner);
+    if(NS_FAILED(nsres))
+        return NULL;
+
+    nsres = nsIPluginTagInfo_GetDOMElement(tag_info, &elem);
+    nsIPluginTagInfo_Release(tag_info);
+    if(NS_FAILED(nsres))
+        return NULL;
+
+    return elem;
+}
+
+static HTMLWindow *get_elem_window(nsIDOMElement *elem)
+{
+    nsIDOMWindow *nswindow;
+    nsIDOMDocument *nsdoc;
+    HTMLWindow *window;
+    nsresult nsres;
+
+    nsres = nsIDOMElement_GetOwnerDocument(elem, &nsdoc);
+    if(NS_FAILED(nsres))
+        return NULL;
+
+    nswindow = get_nsdoc_window(nsdoc);
+    nsIDOMDocument_Release(nsdoc);
+    if(!nswindow)
+        return NULL;
+
+    window = nswindow_to_window(nswindow);
+    nsIDOMWindow_Release(nswindow);
+
+    return window;
+}
+
+static BOOL parse_classid(const PRUnichar *classid, CLSID *clsid)
+{
+    const WCHAR *ptr;
+    unsigned len;
+    HRESULT hres;
+
+    static const PRUnichar clsidW[] = {'c','l','s','i','d',':'};
+
+    if(strncmpW(classid, clsidW, sizeof(clsidW)/sizeof(WCHAR)))
+        return FALSE;
+
+    ptr = classid + sizeof(clsidW)/sizeof(WCHAR);
+    len = strlenW(ptr);
+
+    if(len == 38) {
+        hres = CLSIDFromString(ptr, clsid);
+    }else if(len == 36) {
+        WCHAR buf[39];
+
+        buf[0] = '{';
+        memcpy(buf+1, ptr, len*sizeof(WCHAR));
+        buf[37] = '}';
+        buf[38] = 0;
+        hres = CLSIDFromString(buf, clsid);
+    }else {
+        return FALSE;
+    }
+
+    return SUCCEEDED(hres);
+}
+
+static BOOL get_elem_clsid(nsIDOMElement *elem, CLSID *clsid)
+{
+    nsAString attr_str, val_str;
+    nsresult nsres;
+    BOOL ret = FALSE;
+
+    static const PRUnichar classidW[] = {'c','l','a','s','s','i','d',0};
+
+    nsAString_InitDepend(&attr_str, classidW);
+    nsAString_Init(&val_str, NULL);
+    nsres = nsIDOMElement_GetAttribute(elem, &attr_str, &val_str);
+    nsAString_Finish(&attr_str);
+    if(NS_SUCCEEDED(nsres)) {
+        const PRUnichar *val;
+
+        nsAString_GetData(&val_str, &val);
+        if(*val)
+            ret = parse_classid(val, clsid);
+    }else {
+        ERR("GetAttribute failed: %08x\n", nsres);
+    }
+
+    nsAString_Finish(&attr_str);
+    return ret;
+}
+
+static IUnknown *create_activex_object(HTMLWindow *window, nsIDOMElement *nselem)
+{
+    IClassFactoryEx *cfex;
+    IClassFactory *cf;
+    IUnknown *obj;
+    DWORD policy;
+    CLSID guid;
+    HRESULT hres;
+
+    if(!get_elem_clsid(nselem, &guid)) {
+        WARN("Could not determine element CLSID\n");
+        return NULL;
+    }
+
+    TRACE("clsid %s\n", debugstr_guid(&guid));
+
+    policy = 0;
+    hres = IInternetHostSecurityManager_ProcessUrlAction(HOSTSECMGR(window->doc), URLACTION_ACTIVEX_RUN,
+            (BYTE*)&policy, sizeof(policy), (BYTE*)&guid, sizeof(GUID), 0, 0);
+    if(FAILED(hres) || policy != URLPOLICY_ALLOW) {
+        WARN("ProcessUrlAction returned %08x %x\n", hres, policy);
+        return NULL;
+    }
+
+    hres = CoGetClassObject(&guid, CLSCTX_INPROC_SERVER|CLSCTX_LOCAL_SERVER, NULL, &IID_IClassFactory, (void**)&cf);
+    if(FAILED(hres))
+        return NULL;
+
+    hres = IClassFactory_QueryInterface(cf, &IID_IClassFactoryEx, (void**)&cfex);
+    if(SUCCEEDED(hres)) {
+        FIXME("Use IClassFactoryEx\n");
+        IClassFactoryEx_Release(cfex);
+    }
+
+    hres = IClassFactory_CreateInstance(cf, NULL, &IID_IUnknown, (void**)&obj);
+    if(FAILED(hres))
+        return NULL;
+
+    return obj;
+}
+
 static NPError CDECL NPP_New(NPMIMEType pluginType, NPP instance, UINT16 mode, INT16 argc, char **argn,
         char **argv, NPSavedData *saved)
 {
-    FIXME("(%s %p %x %d %p %p %p)\n", debugstr_a(pluginType), instance, mode, argc, argn, argv, saved);
-    return NPERR_GENERIC_ERROR;
+    nsIDOMElement *nselem;
+    HTMLWindow *window;
+    IUnknown *obj;
+    NPError err = NPERR_NO_ERROR;
+
+    TRACE("(%s %p %x %d %p %p %p)\n", debugstr_a(pluginType), instance, mode, argc, argn, argv, saved);
+
+    nselem = get_dom_element(instance);
+    if(!nselem) {
+        ERR("Could not get DOM element\n");
+        return NPERR_GENERIC_ERROR;
+    }
+
+    window = get_elem_window(nselem);
+    if(!window) {
+        ERR("Could not get element's window object\n");
+        nsIDOMElement_Release(nselem);
+        return NPERR_GENERIC_ERROR;
+    }
+
+    obj = create_activex_object(window, nselem);
+    if(obj) {
+        FIXME("Embed objet %p\n", obj);
+        IUnknown_Release(obj);
+    }else {
+        err = NPERR_GENERIC_ERROR;
+    }
+
+    nsIDOMElement_Release(nselem);
+    return err;
 }
 
 static NPError CDECL NPP_Destroy(NPP instance, NPSavedData **save)
diff --git a/dlls/mshtml/nsiface.idl b/dlls/mshtml/nsiface.idl
index 48d4f6c090f..9e2e484ed3a 100644
--- a/dlls/mshtml/nsiface.idl
+++ b/dlls/mshtml/nsiface.idl
@@ -148,6 +148,8 @@ typedef nsISupports nsITransferable;
 typedef nsISupports nsIDOMHTMLHeadElement;
 typedef nsISupports nsIDOMFileList;
 typedef nsISupports nsIControllers;
+typedef nsISupports nsIPluginInstanceOwner;
+typedef nsISupports nsIPluginStreamListener;
 
 [
     object,
@@ -3018,3 +3020,76 @@ typedef struct _NPPrint {
         NPEmbedPrint embedPrint;
     } print;
 } NPPrint;
+
+typedef HRGN NPRegion;
+
+[
+    object,
+    uuid(84994340-e120-4051-824f-d4ee8aef1a3e),
+    local
+]
+interface nsIPluginInstance : nsISupports
+{
+    typedef void *JSContext;
+    typedef void *JSObject;
+
+    nsresult Initialize(nsIPluginInstanceOwner *aOwner, const char *aMIMEType);
+    nsresult Start();
+    nsresult Stop();
+    nsresult SetWindow(NPWindow *aWindow);
+    nsresult NewStreamToPlugin(nsIPluginStreamListener **aListener);
+    nsresult NewStreamFromPlugin(const char *aType, const char *aTarget, nsIOutputStream **aResult);
+    nsresult Print(NPPrint *aPlatformPrint);
+    nsresult HandleEvent(void *aEvent, PRInt16 *aHandled);
+    nsresult InvalidateRect(NPRect *aRect);
+    nsresult InvalidateRegion(NPRegion aRegion);
+    nsresult ForceRedraw();
+    nsresult GetMIMEType(const char **aValue);
+    nsresult GetJSContext(JSContext **aJSContext);
+    nsresult GetOwner(nsIPluginInstanceOwner **aOwner);
+    nsresult SetOwner(nsIPluginInstanceOwner *aOwner);
+    nsresult ShowStatus(const char *aMessage);
+    nsresult InvalidateOwner();
+    nsresult GetJSObject(JSContext *cx, JSObject **_retval);
+    nsresult GetFormValue(nsAString *aFormValue);
+    nsresult PushPopupsEnabledState(PRBool aEnabled);
+    nsresult PopPopupsEnabledState();
+    nsresult GetPluginAPIVersion(PRUint16 *aPluginAPIVersion);
+    nsresult DefineJavaProperties();
+    nsresult ShouldCache(PRBool *_retval);
+    nsresult IsWindowless(PRBool *_retval);
+    nsresult IsTransparent(PRBool *_retval);
+    nsresult GetValueFromPlugin(NPPVariable variable, void *aValue);
+    nsresult GetDrawingModel(PRInt32 *_retval);
+}
+
+[
+    object,
+    uuid(6d827df5-b5cd-416c-85cb-3cdd05c7aed1),
+    local
+]
+interface nsIPluginTagInfo : nsISupports
+{
+    typedef enum {
+        nsPluginTagType_Unknown,
+        nsPluginTagType_Embed,
+        nsPluginTagType_Object,
+        nsPluginTagType_Applet
+    }  nsPluginTagType;
+
+    nsresult GetAttributes(PRUint16 *aCount, const char ***aNames, const char ***aValues);
+    nsresult GetAttribute(const char *aName, const char **aResult);
+    nsresult GetTagType(nsPluginTagType *aTagType);
+    nsresult GetTagText(const char **aTagText);
+    nsresult GetParameters(PRUint16 *aCount, const char ***aNames, const char ***aValues);
+    nsresult GetParameter(const char *aName, const char **aResult);
+    nsresult GetDocumentBase(const char **aDocumentBase);
+    nsresult GetDocumentEncoding(const char **aDocumentEncoding);
+    nsresult GetAlignment(const char **aElignment);
+    nsresult GetWidth(PRUint32 *aWidth);
+    nsresult GetHeight(PRUint32 *aHeight);
+    nsresult GetBorderVertSpace(PRUint32 *aBorderVertSpace);
+    nsresult GetBorderHorizSpace(PRUint32 *aBorderHorizSpace);
+    nsresult GetUniqueID(PRUint32 *aUniqueID);
+    nsresult GetDOMElement(nsIDOMElement **aDOMElement);
+}
diff --git a/dlls/mshtml/tests/activex.c b/dlls/mshtml/tests/activex.c
index f9e148ed4af..f080c1dd308 100644
--- a/dlls/mshtml/tests/activex.c
+++ b/dlls/mshtml/tests/activex.c
@@ -659,7 +659,7 @@ static IHTMLDocument2 *create_document(void)
     return doc;
 }
 
-static IHTMLDocument2 *create_doc(const char *str)
+static IHTMLDocument2 *create_doc(const char *str, BOOL *b)
 {
     IHTMLDocument2 *doc;
     MSG msg;
@@ -669,7 +669,7 @@ static IHTMLDocument2 *create_doc(const char *str)
     doc_load_string(doc, str);
     do_advise((IUnknown*)doc, &IID_IPropertyNotifySink, (IUnknown*)&PropertyNotifySink);
 
-    while(!doc_complete && GetMessage(&msg, NULL, 0, 0)) {
+    while((!doc_complete || (b && !*b)) && GetMessage(&msg, NULL, 0, 0)) {
         TranslateMessage(&msg);
         DispatchMessage(&msg);
     }
@@ -690,9 +690,13 @@ static void test_object_ax(void)
 {
     IHTMLDocument2 *doc;
 
+    /*
+     * We pump messages until both document is loaded and plugin instance is created.
+     * Pumping until document is loaded should be enough, but Gecko loads plugins
+     * asynchronously and until we'll work around it, we need this hack.
+     */
     SET_EXPECT(CreateInstance);
-    doc = create_doc(object_ax_str);
-    todo_wine
+    doc = create_doc(object_ax_str, &called_CreateInstance);
     CHECK_CALLED(CreateInstance);
 
     release_doc(doc);
-- 
GitLab