|  | /* | 
|  | * Copyright 2010 Jacek Caban for CodeWeavers | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library 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 | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  |  | 
|  | #include <stdarg.h> | 
|  |  | 
|  | #define COBJMACROS | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winuser.h" | 
|  | #include "ole2.h" | 
|  | #include "shlobj.h" | 
|  |  | 
|  | #include "mshtml_private.h" | 
|  | #include "pluginhost.h" | 
|  |  | 
|  | #include "wine/debug.h" | 
|  | #include "wine/unicode.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(mshtml); | 
|  |  | 
|  | /* Parts of npapi.h */ | 
|  |  | 
|  | #define NPERR_BASE                         0 | 
|  | #define NPERR_NO_ERROR                    (NPERR_BASE + 0) | 
|  | #define NPERR_GENERIC_ERROR               (NPERR_BASE + 1) | 
|  | #define NPERR_INVALID_INSTANCE_ERROR      (NPERR_BASE + 2) | 
|  | #define NPERR_INVALID_FUNCTABLE_ERROR     (NPERR_BASE + 3) | 
|  | #define NPERR_MODULE_LOAD_FAILED_ERROR    (NPERR_BASE + 4) | 
|  | #define NPERR_OUT_OF_MEMORY_ERROR         (NPERR_BASE + 5) | 
|  | #define NPERR_INVALID_PLUGIN_ERROR        (NPERR_BASE + 6) | 
|  | #define NPERR_INVALID_PLUGIN_DIR_ERROR    (NPERR_BASE + 7) | 
|  | #define NPERR_INCOMPATIBLE_VERSION_ERROR  (NPERR_BASE + 8) | 
|  | #define NPERR_INVALID_PARAM               (NPERR_BASE + 9) | 
|  | #define NPERR_INVALID_URL                 (NPERR_BASE + 10) | 
|  | #define NPERR_FILE_NOT_FOUND              (NPERR_BASE + 11) | 
|  | #define NPERR_NO_DATA                     (NPERR_BASE + 12) | 
|  | #define NPERR_STREAM_NOT_SEEKABLE         (NPERR_BASE + 13) | 
|  |  | 
|  | /* Parts of npfunctions.h */ | 
|  |  | 
|  | typedef NPError (CDECL *NPP_NewProcPtr)(NPMIMEType,NPP,UINT16,INT16,char**,char**,NPSavedData*); | 
|  | typedef NPError (CDECL *NPP_DestroyProcPtr)(NPP,NPSavedData**); | 
|  | typedef NPError (CDECL *NPP_SetWindowProcPtr)(NPP,NPWindow*); | 
|  | typedef NPError (CDECL *NPP_NewStreamProcPtr)(NPP,NPMIMEType,NPStream*,NPBool,UINT16*); | 
|  | typedef NPError (CDECL *NPP_DestroyStreamProcPtr)(NPP,NPStream*,NPReason); | 
|  | typedef INT32 (CDECL *NPP_WriteReadyProcPtr)(NPP,NPStream*); | 
|  | typedef INT32 (CDECL *NPP_WriteProcPtr)(NPP,NPStream*,INT32,INT32,void*); | 
|  | typedef void (CDECL *NPP_StreamAsFileProcPtr)(NPP,NPStream*,const char*); | 
|  | typedef void (CDECL *NPP_PrintProcPtr)(NPP,NPPrint*); | 
|  | typedef INT16 (CDECL *NPP_HandleEventProcPtr)(NPP,void*); | 
|  | typedef void (CDECL *NPP_URLNotifyProcPtr)(NPP,const char*,NPReason,void*); | 
|  | typedef NPError (CDECL *NPP_GetValueProcPtr)(NPP,NPPVariable,void*); | 
|  | typedef NPError (CDECL *NPP_SetValueProcPtr)(NPP,NPNVariable,void*); | 
|  | typedef NPBool (CDECL *NPP_GotFocusPtr)(NPP,NPFocusDirection); | 
|  | typedef void (CDECL *NPP_LostFocusPtr)(NPP); | 
|  |  | 
|  | typedef struct _NPPluginFuncs { | 
|  | UINT16 size; | 
|  | UINT16 version; | 
|  | NPP_NewProcPtr newp; | 
|  | NPP_DestroyProcPtr destroy; | 
|  | NPP_SetWindowProcPtr setwindow; | 
|  | NPP_NewStreamProcPtr newstream; | 
|  | NPP_DestroyStreamProcPtr destroystream; | 
|  | NPP_StreamAsFileProcPtr asfile; | 
|  | NPP_WriteReadyProcPtr writeready; | 
|  | NPP_WriteProcPtr write; | 
|  | NPP_PrintProcPtr print; | 
|  | NPP_HandleEventProcPtr event; | 
|  | NPP_URLNotifyProcPtr urlnotify; | 
|  | void *javaClass; | 
|  | NPP_GetValueProcPtr getvalue; | 
|  | NPP_SetValueProcPtr setvalue; | 
|  | NPP_GotFocusPtr gotfocus; | 
|  | 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(strncmpiW(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, CLSID *clsid) | 
|  | { | 
|  | IClassFactoryEx *cfex; | 
|  | IClassFactory *cf; | 
|  | IUnknown *obj; | 
|  | DWORD policy; | 
|  | HRESULT hres; | 
|  |  | 
|  | if(!get_elem_clsid(nselem, clsid)) { | 
|  | WARN("Could not determine element CLSID\n"); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | TRACE("clsid %s\n", debugstr_guid(clsid)); | 
|  |  | 
|  | policy = 0; | 
|  | hres = IInternetHostSecurityManager_ProcessUrlAction(&window->doc->IInternetHostSecurityManager_iface, | 
|  | URLACTION_ACTIVEX_RUN, (BYTE*)&policy, sizeof(policy), (BYTE*)clsid, sizeof(GUID), 0, 0); | 
|  | if(FAILED(hres) || policy != URLPOLICY_ALLOW) { | 
|  | WARN("ProcessUrlAction returned %08x %x\n", hres, policy); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | hres = CoGetClassObject(clsid, 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) | 
|  | { | 
|  | nsIDOMElement *nselem; | 
|  | HTMLWindow *window; | 
|  | IUnknown *obj; | 
|  | CLSID clsid; | 
|  | 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, &clsid); | 
|  | if(obj) { | 
|  | PluginHost *host; | 
|  | HRESULT hres; | 
|  |  | 
|  | hres = create_plugin_host(window->doc, nselem, obj, &clsid, &host); | 
|  | nsIDOMElement_Release(nselem); | 
|  | IUnknown_Release(obj); | 
|  | if(SUCCEEDED(hres)) | 
|  | instance->pdata = host; | 
|  | else | 
|  | err = NPERR_GENERIC_ERROR; | 
|  | }else { | 
|  | err = NPERR_GENERIC_ERROR; | 
|  | } | 
|  |  | 
|  | nsIDOMElement_Release(nselem); | 
|  | return err; | 
|  | } | 
|  |  | 
|  | static NPError CDECL NPP_Destroy(NPP instance, NPSavedData **save) | 
|  | { | 
|  | PluginHost *host = instance->pdata; | 
|  |  | 
|  | TRACE("(%p %p)\n", instance, save); | 
|  |  | 
|  | if(!host) | 
|  | return NPERR_GENERIC_ERROR; | 
|  |  | 
|  | detach_plugin_host(host); | 
|  | IOleClientSite_Release(&host->IOleClientSite_iface); | 
|  | instance->pdata = NULL; | 
|  | return NPERR_NO_ERROR; | 
|  | } | 
|  |  | 
|  | static NPError CDECL NPP_SetWindow(NPP instance, NPWindow *window) | 
|  | { | 
|  | PluginHost *host = instance->pdata; | 
|  | RECT pos_rect = {0, 0, window->width, window->height}; | 
|  |  | 
|  | TRACE("(%p %p)\n", instance, window); | 
|  |  | 
|  | if(!host) | 
|  | return NPERR_GENERIC_ERROR; | 
|  |  | 
|  | update_plugin_window(host, window->window, &pos_rect); | 
|  | return NPERR_NO_ERROR; | 
|  | } | 
|  |  | 
|  | static NPError CDECL NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable, UINT16 *stype) | 
|  | { | 
|  | TRACE("\n"); | 
|  | return NPERR_GENERIC_ERROR; | 
|  | } | 
|  |  | 
|  | static NPError CDECL NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason) | 
|  | { | 
|  | TRACE("\n"); | 
|  | return NPERR_GENERIC_ERROR; | 
|  | } | 
|  |  | 
|  | static INT32 CDECL NPP_WriteReady(NPP instance, NPStream *stream) | 
|  | { | 
|  | TRACE("\n"); | 
|  | return NPERR_GENERIC_ERROR; | 
|  | } | 
|  |  | 
|  | static INT32 CDECL NPP_Write(NPP instance, NPStream *stream, INT32 offset, INT32 len, void *buffer) | 
|  | { | 
|  | TRACE("\n"); | 
|  | return NPERR_GENERIC_ERROR; | 
|  | } | 
|  |  | 
|  | static void CDECL NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname) | 
|  | { | 
|  | TRACE("\n"); | 
|  | } | 
|  |  | 
|  | static void CDECL NPP_Print(NPP instance, NPPrint *platformPrint) | 
|  | { | 
|  | FIXME("\n"); | 
|  | } | 
|  |  | 
|  | static INT16 CDECL NPP_HandleEvent(NPP instance, void *event) | 
|  | { | 
|  | TRACE("\n"); | 
|  | return NPERR_GENERIC_ERROR; | 
|  | } | 
|  |  | 
|  | static void CDECL NPP_URLNotify(NPP instance, const char *url, NPReason reason, void *notifyData) | 
|  | { | 
|  | TRACE("\n"); | 
|  | } | 
|  |  | 
|  | static NPError CDECL NPP_GetValue(NPP instance, NPPVariable variable, void *ret_value) | 
|  | { | 
|  | TRACE("\n"); | 
|  | return NPERR_GENERIC_ERROR; | 
|  | } | 
|  |  | 
|  | static NPError CDECL NPP_SetValue(NPP instance, NPNVariable variable, void *value) | 
|  | { | 
|  | TRACE("\n"); | 
|  | return NPERR_GENERIC_ERROR; | 
|  | } | 
|  |  | 
|  | static NPBool CDECL NPP_GotFocus(NPP instance, NPFocusDirection direction) | 
|  | { | 
|  | FIXME("\n"); | 
|  | return NPERR_GENERIC_ERROR; | 
|  | } | 
|  |  | 
|  | static void CDECL NPP_LostFocus(NPP instance) | 
|  | { | 
|  | FIXME("\n"); | 
|  | } | 
|  |  | 
|  | /*********************************************************************** | 
|  | *          NP_GetEntryPoints (mshtml.@) | 
|  | */ | 
|  | NPError WINAPI NP_GetEntryPoints(NPPluginFuncs* funcs) | 
|  | { | 
|  | TRACE("(%p)\n", funcs); | 
|  |  | 
|  | funcs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR; | 
|  | funcs->newp = NPP_New; | 
|  | funcs->destroy = NPP_Destroy; | 
|  | funcs->setwindow = NPP_SetWindow; | 
|  | funcs->newstream = NPP_NewStream; | 
|  | funcs->destroystream = NPP_DestroyStream; | 
|  | funcs->asfile = NPP_StreamAsFile; | 
|  | funcs->writeready = NPP_WriteReady; | 
|  | funcs->write = NPP_Write; | 
|  | funcs->print = NPP_Print; | 
|  | funcs->event = NPP_HandleEvent; | 
|  | funcs->urlnotify = NPP_URLNotify; | 
|  | funcs->javaClass = NULL; | 
|  | funcs->getvalue = NPP_GetValue; | 
|  | funcs->setvalue = NPP_SetValue; | 
|  | funcs->gotfocus = NPP_GotFocus; | 
|  | funcs->lostfocus = NPP_LostFocus; | 
|  |  | 
|  | return NPERR_NO_ERROR; | 
|  | } |