| /* |
| * Copyright 2005 Jacek Caban |
| * |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #include "config.h" |
| |
| #include <stdarg.h> |
| |
| #define COBJMACROS |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "winuser.h" |
| #include "winreg.h" |
| #include "ole2.h" |
| |
| #include "wine/debug.h" |
| #include "wine/unicode.h" |
| |
| #include "mshtml_private.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(mshtml); |
| |
| DEFINE_GUID(CLSID_StartupNotifier, 0x1f59b001,0x02c9,0x11d5,0xae,0x76,0xcc,0x92,0xf7,0xdb,0x9e,0x03); |
| DEFINE_GUID(CLSID_nsWebBrowser, 0xf1eac761,0x87e9,0x11d3,0xaf,0x80,0x00,0xa0,0x24,0xff,0xc0,0x8c); |
| |
| #define NS_APPSTARTUPNOTIFIER_CONTRACTID "@mozilla.org/embedcomp/appstartup-notifier;1" |
| #define NS_WEBBROWSER_CONTRACTID "@mozilla.org/embedding/browser/nsWebBrowser;1" |
| #define NS_IOSERVICE_CONTRACTID "@mozilla.org/network/io-service;1" |
| |
| #define APPSTARTUP_TOPIC "app-startup" |
| |
| #define PR_UINT32_MAX 0xffffffff |
| |
| typedef struct nsACString { |
| void *d1; |
| PRUint32 d2; |
| void *d3; |
| } nsString; |
| |
| static nsresult (*NS_InitXPCOM2)(nsIServiceManager**,void*,void*); |
| static nsresult (*NS_ShutdownXPCOM)(nsIServiceManager*); |
| static nsresult (*NS_StringContainerInit)(nsString*); |
| static nsresult (*NS_CStringContainerInit)(nsACString*); |
| static nsresult (*NS_StringContainerFinish)(nsString*); |
| static nsresult (*NS_CStringContainerFinish)(nsACString*); |
| static nsresult (*NS_StringSetData)(nsString*,const PRUnichar*,PRUint32); |
| static nsresult (*NS_CStringSetData)(nsString*,const char*,PRUint32); |
| static nsresult (*NS_NewLocalFile)(const nsString*,PRBool,nsIFile**); |
| |
| static HINSTANCE hXPCOM = NULL; |
| |
| static nsIServiceManager *pServMgr = NULL; |
| static nsIComponentManager *pCompMgr = NULL; |
| static nsIIOService *pIOService = NULL; |
| |
| static const WCHAR wszNsContainer[] = {'N','s','C','o','n','t','a','i','n','e','r',0}; |
| |
| static ATOM nscontainer_class; |
| |
| static LRESULT WINAPI nsembed_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) |
| { |
| HTMLDocument *This; |
| nsresult nsres; |
| |
| static const WCHAR wszTHIS[] = {'T','H','I','S',0}; |
| |
| if(msg == WM_CREATE) { |
| This = *(HTMLDocument**)lParam; |
| SetPropW(hwnd, wszTHIS, This); |
| }else { |
| This = (HTMLDocument*)GetPropW(hwnd, wszTHIS); |
| } |
| |
| switch(msg) { |
| case WM_SIZE: |
| TRACE("(%p)->(WM_SIZE)\n", This); |
| |
| nsres = nsIBaseWindow_SetSize(This->nscontainer->window, |
| LOWORD(lParam), HIWORD(lParam), TRUE); |
| if(NS_FAILED(nsres)) |
| WARN("SetSize failed: %08lx\n", nsres); |
| } |
| |
| return DefWindowProcW(hwnd, msg, wParam, lParam); |
| } |
| |
| |
| static void register_nscontainer_class(void) |
| { |
| static WNDCLASSEXW wndclass = { |
| sizeof(WNDCLASSEXW), |
| CS_DBLCLKS, |
| nsembed_proc, |
| 0, 0, NULL, NULL, NULL, NULL, NULL, |
| wszNsContainer, |
| NULL, |
| }; |
| wndclass.hInstance = hInst; |
| nscontainer_class = RegisterClassExW(&wndclass); |
| } |
| |
| static BOOL get_mozilla_path(PRUnichar *gre_path) |
| { |
| DWORD res, type, i, size = MAX_PATH; |
| HKEY mozilla_key, hkey; |
| WCHAR key_name[100]; |
| BOOL ret = FALSE; |
| |
| static const WCHAR wszGreKey[] = |
| {'S','o','f','t','w','a','r','e','\\', |
| 'm','o','z','i','l','l','a','.','o','r','g','\\', |
| 'G','R','E',0}; |
| |
| static const WCHAR wszGreHome[] = {'G','r','e','H','o','m','e',0}; |
| |
| res = RegOpenKeyW(HKEY_LOCAL_MACHINE, wszGreKey, &mozilla_key); |
| if(res != ERROR_SUCCESS) { |
| TRACE("Could not open key %s\n", debugstr_w(wszGreKey)); |
| return FALSE; |
| } |
| |
| for(i=0; !ret && RegEnumKeyW(mozilla_key, i, key_name, sizeof(key_name)/sizeof(WCHAR)) == ERROR_SUCCESS; i++) { |
| RegOpenKeyW(mozilla_key, key_name, &hkey); |
| res = RegQueryValueExW(hkey, wszGreHome, NULL, &type, (LPBYTE)gre_path, &size); |
| if(res == ERROR_SUCCESS) |
| ret = TRUE; |
| RegCloseKey(hkey); |
| } |
| |
| RegCloseKey(mozilla_key); |
| return ret; |
| } |
| |
| static BOOL get_mozctl_path(PRUnichar *gre_path) |
| { |
| HKEY hkey; |
| DWORD res, type, size = MAX_PATH; |
| |
| static const WCHAR wszMozCtlKey[] = |
| {'S','o','f','t','w','a','r','e','\\','M','o','z','i','l','l','a',0}; |
| static const WCHAR wszBinDirectoryPath[] = |
| {'B','i','n','D','i','r','e','c','t','o','r','y','P','a','t','h',0}; |
| |
| res = RegOpenKeyW(HKEY_LOCAL_MACHINE, wszMozCtlKey, &hkey); |
| if(res != ERROR_SUCCESS) { |
| TRACE("Could not open key %s\n", debugstr_w(wszMozCtlKey)); |
| return FALSE; |
| } |
| |
| res = RegQueryValueExW(hkey, wszBinDirectoryPath, NULL, &type, (LPBYTE)gre_path, &size); |
| if(res != ERROR_SUCCESS) { |
| ERR("Could not get value %s\n", debugstr_w(wszBinDirectoryPath)); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| static BOOL load_gecko() |
| { |
| nsresult nsres; |
| nsIObserver *pStartNotif; |
| nsString path; |
| nsIFile *gre_dir; |
| PRUnichar gre_path[MAX_PATH]; |
| |
| static BOOL tried_load = FALSE; |
| static const WCHAR strXPCOM[] = {'x','p','c','o','m','.','d','l','l',0}; |
| |
| TRACE("()\n"); |
| |
| if(tried_load) |
| return pCompMgr != NULL; |
| tried_load = TRUE; |
| |
| if(!get_mozctl_path(gre_path) && !get_mozilla_path(gre_path)) { |
| MESSAGE("Could not load Mozilla. HTML rendering will be disabled.\n"); |
| return FALSE; |
| } |
| |
| TRACE("found path %s\n", debugstr_w(gre_path)); |
| |
| hXPCOM = LoadLibraryW(strXPCOM); |
| if(!hXPCOM) { |
| /* We have to modify PATH as XPCOM loads other DLLs from this directory. */ |
| WCHAR path_env[MAX_PATH]; |
| static WCHAR wszPATH[] = {'P','A','T','H',0}; |
| int len; |
| |
| GetEnvironmentVariableW(wszPATH, path_env, sizeof(path_env)/sizeof(WCHAR)); |
| len = strlenW(path_env); |
| path_env[len++] = ';'; |
| strcpyW(path_env+len, gre_path); |
| SetEnvironmentVariableW(wszPATH, path_env); |
| |
| hXPCOM = LoadLibraryW(strXPCOM); |
| if(!hXPCOM) { |
| ERR("Could not load XPCOM: %ld\n", GetLastError()); |
| return FALSE; |
| } |
| } |
| |
| #define NS_DLSYM(func) \ |
| func = (typeof(func))GetProcAddress(hXPCOM, #func); \ |
| if(!func) \ |
| ERR("Could not GetProcAddress(" #func ") failed\n") |
| |
| NS_DLSYM(NS_InitXPCOM2); |
| NS_DLSYM(NS_ShutdownXPCOM); |
| NS_DLSYM(NS_StringContainerInit); |
| NS_DLSYM(NS_CStringContainerInit); |
| NS_DLSYM(NS_StringContainerFinish); |
| NS_DLSYM(NS_CStringContainerFinish); |
| NS_DLSYM(NS_StringSetData); |
| NS_DLSYM(NS_CStringSetData); |
| NS_DLSYM(NS_NewLocalFile); |
| |
| #undef NS_DLSYM |
| |
| NS_StringContainerInit(&path); |
| NS_StringSetData(&path, gre_path, PR_UINT32_MAX); |
| nsres = NS_NewLocalFile(&path, FALSE, &gre_dir); |
| NS_StringContainerFinish(&path); |
| if(NS_FAILED(nsres)) { |
| ERR("NS_NewLocalFile failed: %08lx\n", nsres); |
| FreeLibrary(hXPCOM); |
| return FALSE; |
| } |
| |
| nsres = NS_InitXPCOM2(&pServMgr, gre_dir, NULL); |
| if(NS_FAILED(nsres)) { |
| ERR("NS_InitXPCOM2 failed: %08lx\n", nsres); |
| FreeLibrary(hXPCOM); |
| return FALSE; |
| } |
| |
| nsres = nsIServiceManager_QueryInterface(pServMgr, &IID_nsIComponentManager, (void**)&pCompMgr); |
| if(NS_FAILED(nsres)) |
| ERR("Could not get nsIComponentManager: %08lx\n", nsres); |
| |
| nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_APPSTARTUPNOTIFIER_CONTRACTID, |
| NULL, &IID_nsIObserver, (void**)&pStartNotif); |
| if(NS_SUCCEEDED(nsres)) { |
| nsres = nsIObserver_Observe(pStartNotif, NULL, APPSTARTUP_TOPIC, NULL); |
| if(NS_FAILED(nsres)) |
| ERR("Observe failed: %08lx\n", nsres); |
| |
| nsIObserver_Release(pStartNotif); |
| }else { |
| ERR("could not get appstartup-notifier: %08lx\n", nsres); |
| } |
| |
| return TRUE; |
| } |
| |
| nsACString *nsACString_Create(void) |
| { |
| nsACString *ret; |
| ret = HeapAlloc(GetProcessHeap(), 0, sizeof(nsACString)); |
| NS_CStringContainerInit(ret); |
| return ret; |
| } |
| |
| void nsACString_SetData(nsACString *str, const char *data) |
| { |
| NS_CStringSetData(str, data, PR_UINT32_MAX); |
| } |
| |
| void nsACString_Destroy(nsACString *str) |
| { |
| NS_CStringContainerFinish(str); |
| HeapFree(GetProcessHeap(), 0, str); |
| } |
| |
| void close_gecko() |
| { |
| TRACE("()\n"); |
| |
| if(pCompMgr) |
| nsIComponentManager_Release(pCompMgr); |
| |
| if(pServMgr) |
| nsIServiceManager_Release(pServMgr); |
| |
| if(hXPCOM) |
| FreeLibrary(hXPCOM); |
| } |
| |
| nsIURI *get_nsIURI(LPCWSTR url) |
| { |
| nsIURI *ret; |
| nsACString *acstr; |
| nsresult nsres; |
| char *urla; |
| int len; |
| |
| if(!pIOService) { |
| nsres = nsIServiceManager_GetServiceByContactID(pServMgr, NS_IOSERVICE_CONTRACTID, |
| &IID_nsIIOService, (void**)&pIOService); |
| if(NS_FAILED(nsres)) |
| ERR("Failed to create nsIOService: %08lx\n", nsres); |
| } |
| |
| len = WideCharToMultiByte(CP_ACP, 0, url, -1, NULL, -1, NULL, NULL); |
| urla = HeapAlloc(GetProcessHeap(), 0, len); |
| WideCharToMultiByte(CP_ACP, 0, url, -1, urla, -1, NULL, NULL); |
| |
| acstr = nsACString_Create(); |
| nsACString_SetData(acstr, urla); |
| |
| nsres = nsIIOService_NewURI(pIOService, acstr, NULL, NULL, &ret); |
| if(NS_FAILED(nsres)) |
| FIXME("NewURI failed: %08lx\n", nsres); |
| |
| nsACString_Destroy(acstr); |
| HeapFree(GetProcessHeap(), 0, urla); |
| |
| return ret; |
| } |
| |
| void HTMLDocument_NSContainer_Init(HTMLDocument *This) |
| { |
| nsIWebBrowserSetup *wbsetup; |
| nsresult nsres; |
| |
| This->nscontainer = NULL; |
| |
| if(!load_gecko()) |
| return; |
| |
| This->nscontainer = HeapAlloc(GetProcessHeap(), 0, sizeof(NSContainer)); |
| |
| nsres = nsIComponentManager_CreateInstanceByContractID(pCompMgr, NS_WEBBROWSER_CONTRACTID, |
| NULL, &IID_nsIWebBrowser, (void**)&This->nscontainer->webbrowser); |
| if(NS_FAILED(nsres)) |
| ERR("Creating WebBrowser failed: %08lx\n", nsres); |
| |
| nsres = nsIWebBrowser_QueryInterface(This->nscontainer->webbrowser, &IID_nsIBaseWindow, |
| (void**)&This->nscontainer->window); |
| if(NS_FAILED(nsres)) |
| ERR("Could not get nsIBaseWindow interface: %08lx\n", nsres); |
| |
| nsres = nsIWebBrowser_QueryInterface(This->nscontainer->webbrowser, |
| &IID_nsIWebBrowserSetup, (void**)&wbsetup); |
| if(NS_SUCCEEDED(nsres)) { |
| nsres = nsIWebBrowserSetup_SetProperty(wbsetup, SETUP_IS_CHROME_WRAPPER, TRUE); |
| if(NS_FAILED(nsres)) |
| ERR("SetProperty failed: %08lx\n", nsres); |
| nsIWebBrowserSetup_Release(wbsetup); |
| }else { |
| ERR("Could not get nsIWebBrowserSetup interface\n"); |
| } |
| |
| nsres = nsIWebBrowser_QueryInterface(This->nscontainer->webbrowser, &IID_nsIWebNavigation, |
| (void**)&This->nscontainer->navigation); |
| if(NS_FAILED(nsres)) |
| ERR("Could not get nsIWebNavigation interface: %08lx\n", nsres); |
| |
| nsres = nsIWebBrowserStream_QueryInterface(This->nscontainer->webbrowser, &IID_nsIWebBrowserStream, |
| (void**)&This->nscontainer->stream); |
| if(NS_FAILED(nsres)) |
| ERR("Could not get nsIWebBrowserStream interface: %08lx\n", nsres); |
| |
| if(!nscontainer_class) |
| register_nscontainer_class(); |
| |
| This->nscontainer->hwnd = CreateWindowExW(0, wszNsContainer, NULL, |
| WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, 100, 100, |
| GetDesktopWindow(), NULL, hInst, This); |
| |
| nsres = nsIBaseWindow_InitWindow(This->nscontainer->window, This->nscontainer->hwnd, NULL, |
| 0, 0, 100, 100); |
| if(NS_SUCCEEDED(nsres)) { |
| nsres = nsIBaseWindow_Create(This->nscontainer->window); |
| if(NS_FAILED(nsres)) |
| WARN("Creating window failed: %08lx\n", nsres); |
| |
| nsIBaseWindow_SetVisibility(This->nscontainer->window, FALSE); |
| nsIBaseWindow_SetEnabled(This->nscontainer->window, FALSE); |
| }else { |
| ERR("InitWindow failed: %08lx\n", nsres); |
| } |
| } |
| |
| void HTMLDocument_NSContainer_Destroy(HTMLDocument *This) |
| { |
| TRACE("(%p)\n", This); |
| |
| nsIWebBrowser_Release(This->nscontainer->webbrowser); |
| nsIWebNavigation_Release(This->nscontainer->navigation); |
| nsIBaseWindow_Release(This->nscontainer->window); |
| |
| if(This->nscontainer->stream) |
| nsIWebBrowserStream_Release(This->nscontainer->stream); |
| |
| HeapFree(GetProcessHeap(), 0, This->nscontainer); |
| } |