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