|  | /* | 
|  | * Copyright 2006 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 | 
|  | #define NONAMELESSUNION | 
|  | #define NONAMELESSSTRUCT | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winuser.h" | 
|  | #include "winreg.h" | 
|  | #include "ole2.h" | 
|  | #include "commctrl.h" | 
|  | #include "advpub.h" | 
|  |  | 
|  | #include "wine/debug.h" | 
|  | #include "wine/unicode.h" | 
|  |  | 
|  | #include "mshtml_private.h" | 
|  | #include "resource.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(mshtml); | 
|  |  | 
|  | static HWND install_dialog = NULL; | 
|  | static LPWSTR tmp_file_name = NULL; | 
|  | static HANDLE tmp_file = INVALID_HANDLE_VALUE; | 
|  | static LPWSTR url = NULL; | 
|  |  | 
|  | static void clean_up(void) | 
|  | { | 
|  | if(tmp_file != INVALID_HANDLE_VALUE) | 
|  | CloseHandle(tmp_file); | 
|  |  | 
|  | if(tmp_file_name) { | 
|  | DeleteFileW(tmp_file_name); | 
|  | mshtml_free(tmp_file_name); | 
|  | tmp_file_name = NULL; | 
|  | } | 
|  |  | 
|  | if(tmp_file != INVALID_HANDLE_VALUE) { | 
|  | CloseHandle(tmp_file); | 
|  | tmp_file = INVALID_HANDLE_VALUE; | 
|  | } | 
|  |  | 
|  | if(install_dialog) | 
|  | EndDialog(install_dialog, 0); | 
|  | } | 
|  |  | 
|  | static void set_status(DWORD id) | 
|  | { | 
|  | HWND status = GetDlgItem(install_dialog, ID_DWL_STATUS); | 
|  | WCHAR buf[64]; | 
|  |  | 
|  | LoadStringW(hInst, id, buf, sizeof(buf)/sizeof(WCHAR)); | 
|  | SendMessageW(status, WM_SETTEXT, 0, (LPARAM)buf); | 
|  | } | 
|  |  | 
|  | static void set_registry(LPCSTR install_dir) | 
|  | { | 
|  | LPWSTR gecko_path; | 
|  | HKEY hkey; | 
|  | DWORD res, len, size; | 
|  |  | 
|  | static const WCHAR wszMshtmlKey[] = { | 
|  | 'S','o','f','t','w','a','r','e','\\','W','i','n','e', | 
|  | '\\','M','S','H','T','M','L',0}; | 
|  | static const WCHAR wszGeckoPath[] = {'G','e','c','k','o','P','a','t','h',0}; | 
|  | static const WCHAR wszWineGecko[] = {'w','i','n','e','_','g','e','c','k','o',0}; | 
|  |  | 
|  | /* @@ Wine registry key: HKCU\Software\Wine\MSHTML */ | 
|  | res = RegOpenKeyW(HKEY_CURRENT_USER, wszMshtmlKey, &hkey); | 
|  | if(res != ERROR_SUCCESS) { | 
|  | ERR("Faild to open MSHTML key: %d\n", res); | 
|  | return; | 
|  | } | 
|  |  | 
|  | len = MultiByteToWideChar(CP_ACP, 0, install_dir, -1, NULL, 0)-1; | 
|  | gecko_path = mshtml_alloc((len+1)*sizeof(WCHAR)+sizeof(wszWineGecko)); | 
|  | MultiByteToWideChar(CP_ACP, 0, install_dir, -1, gecko_path, (len+1)*sizeof(WCHAR)); | 
|  |  | 
|  | if (len && gecko_path[len-1] != '\\') | 
|  | gecko_path[len++] = '\\'; | 
|  |  | 
|  | memcpy(gecko_path+len, wszWineGecko, sizeof(wszWineGecko)); | 
|  |  | 
|  | size = len*sizeof(WCHAR)+sizeof(wszWineGecko); | 
|  | res = RegSetValueExW(hkey, wszGeckoPath, 0, REG_SZ, (LPVOID)gecko_path, | 
|  | len*sizeof(WCHAR)+sizeof(wszWineGecko)); | 
|  | mshtml_free(gecko_path); | 
|  | RegCloseKey(hkey); | 
|  | if(res != ERROR_SUCCESS) | 
|  | ERR("Failed to set GeckoPath value: %08x\n", res); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InstallCallback_QueryInterface(IBindStatusCallback *iface, | 
|  | REFIID riid, void **ppv) | 
|  | { | 
|  | if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IBindStatusCallback, riid)) { | 
|  | *ppv = iface; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | return E_INVALIDARG; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI InstallCallback_AddRef(IBindStatusCallback *iface) | 
|  | { | 
|  | return 2; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI InstallCallback_Release(IBindStatusCallback *iface) | 
|  | { | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InstallCallback_OnStartBinding(IBindStatusCallback *iface, | 
|  | DWORD dwReserved, IBinding *pib) | 
|  | { | 
|  | WCHAR tmp_dir[MAX_PATH]; | 
|  |  | 
|  | set_status(IDS_DOWNLOADING); | 
|  |  | 
|  | GetTempPathW(sizeof(tmp_dir)/sizeof(WCHAR), tmp_dir); | 
|  |  | 
|  | tmp_file_name = mshtml_alloc(MAX_PATH*sizeof(WCHAR)); | 
|  | GetTempFileNameW(tmp_dir, NULL, 0, tmp_file_name); | 
|  |  | 
|  | TRACE("creating temp file %s\n", debugstr_w(tmp_file_name)); | 
|  |  | 
|  | tmp_file = CreateFileW(tmp_file_name, GENERIC_WRITE, 0, NULL, | 
|  | CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | 
|  |  | 
|  | if(tmp_file == INVALID_HANDLE_VALUE) { | 
|  | ERR("Could not create file: %d\n", GetLastError()); | 
|  | clean_up(); | 
|  | return E_FAIL; | 
|  | } | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InstallCallback_GetPriority(IBindStatusCallback *iface, | 
|  | LONG *pnPriority) | 
|  | { | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InstallCallback_OnLowResource(IBindStatusCallback *iface, | 
|  | DWORD dwReserved) | 
|  | { | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InstallCallback_OnProgress(IBindStatusCallback *iface, ULONG ulProgress, | 
|  | ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText) | 
|  | { | 
|  | HWND progress = GetDlgItem(install_dialog, ID_DWL_PROGRESS); | 
|  |  | 
|  | if(ulProgressMax) | 
|  | SendMessageW(progress, PBM_SETRANGE32, 0, ulProgressMax); | 
|  | if(ulProgress) | 
|  | SendMessageW(progress, PBM_SETPOS, ulProgress, 0); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InstallCallback_OnStopBinding(IBindStatusCallback *iface, | 
|  | HRESULT hresult, LPCWSTR szError) | 
|  | { | 
|  | LPSTR file_name; | 
|  | DWORD len; | 
|  | HMODULE advpack; | 
|  | char program_files[MAX_PATH]; | 
|  | typeof(ExtractFilesA) *pExtractFilesA; | 
|  | HRESULT hres; | 
|  |  | 
|  | static const WCHAR wszAdvpack[] = {'a','d','v','p','a','c','k','.','d','l','l',0}; | 
|  |  | 
|  | if(FAILED(hresult)) { | 
|  | ERR("Binding failed %08x\n", hresult); | 
|  | clean_up(); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | CloseHandle(tmp_file); | 
|  | tmp_file = INVALID_HANDLE_VALUE; | 
|  |  | 
|  | set_status(IDS_INSTALLING); | 
|  |  | 
|  | advpack = LoadLibraryW(wszAdvpack); | 
|  | pExtractFilesA = (typeof(ExtractFilesA)*)GetProcAddress(advpack, "ExtractFiles"); | 
|  |  | 
|  | len = WideCharToMultiByte(CP_ACP, 0, tmp_file_name, -1, NULL, 0, NULL, NULL); | 
|  | file_name = mshtml_alloc(len); | 
|  | WideCharToMultiByte(CP_ACP, 0, tmp_file_name, -1, file_name, -1, NULL, NULL); | 
|  |  | 
|  | GetEnvironmentVariableA("ProgramFiles", program_files, sizeof(program_files)); | 
|  |  | 
|  | /* FIXME: Use unicode version (not yet implemented) */ | 
|  | hres = pExtractFilesA(file_name, program_files, 0, NULL, NULL, 0); | 
|  | FreeLibrary(advpack); | 
|  | mshtml_free(file_name); | 
|  | if(FAILED(hres)) { | 
|  | ERR("Could not extract package: %08x\n", hres); | 
|  | clean_up(); | 
|  | } | 
|  |  | 
|  | set_registry(program_files); | 
|  | clean_up(); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InstallCallback_GetBindInfo(IBindStatusCallback *iface, | 
|  | DWORD* grfBINDF, BINDINFO* pbindinfo) | 
|  | { | 
|  | /* FIXME */ | 
|  | *grfBINDF = 0; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InstallCallback_OnDataAvailable(IBindStatusCallback *iface, DWORD grfBSCF, | 
|  | DWORD dwSize, FORMATETC* pformatetc, STGMEDIUM* pstgmed) | 
|  | { | 
|  | IStream *str = pstgmed->u.pstm; | 
|  | BYTE buf[1024]; | 
|  | DWORD size; | 
|  | HRESULT hres; | 
|  |  | 
|  | do { | 
|  | size = 0; | 
|  | hres = IStream_Read(str, buf, sizeof(buf), &size); | 
|  | if(size) | 
|  | WriteFile(tmp_file, buf, size, NULL, NULL); | 
|  | }while(hres == S_OK); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI InstallCallback_OnObjectAvailable(IBindStatusCallback *iface, | 
|  | REFIID riid, IUnknown* punk) | 
|  | { | 
|  | ERR("\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static const IBindStatusCallbackVtbl InstallCallbackVtbl = { | 
|  | InstallCallback_QueryInterface, | 
|  | InstallCallback_AddRef, | 
|  | InstallCallback_Release, | 
|  | InstallCallback_OnStartBinding, | 
|  | InstallCallback_GetPriority, | 
|  | InstallCallback_OnLowResource, | 
|  | InstallCallback_OnProgress, | 
|  | InstallCallback_OnStopBinding, | 
|  | InstallCallback_GetBindInfo, | 
|  | InstallCallback_OnDataAvailable, | 
|  | InstallCallback_OnObjectAvailable | 
|  | }; | 
|  |  | 
|  | static IBindStatusCallback InstallCallback = { &InstallCallbackVtbl }; | 
|  |  | 
|  | static LPWSTR get_url(void) | 
|  | { | 
|  | HKEY hkey; | 
|  | DWORD res, type; | 
|  | DWORD size = 512*sizeof(WCHAR); | 
|  | LPWSTR url; | 
|  |  | 
|  | static const WCHAR wszMshtmlKey[] = { | 
|  | 'S','o','f','t','w','a','r','e','\\','W','i','n','e', | 
|  | '\\','M','S','H','T','M','L',0}; | 
|  | static const WCHAR wszGeckoUrl[] = {'G','e','c','k','o','U','r','l',0}; | 
|  |  | 
|  | /* @@ Wine registry key: HKCU\Software\Wine\MSHTML */ | 
|  | res = RegOpenKeyW(HKEY_CURRENT_USER, wszMshtmlKey, &hkey); | 
|  | if(res != ERROR_SUCCESS) | 
|  | return NULL; | 
|  |  | 
|  | url = mshtml_alloc(size); | 
|  |  | 
|  | res = RegQueryValueExW(hkey, wszGeckoUrl, NULL, &type, (LPBYTE)url, &size); | 
|  | RegCloseKey(hkey); | 
|  | if(res != ERROR_SUCCESS || type != REG_SZ) { | 
|  | mshtml_free(url); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return url; | 
|  | } | 
|  |  | 
|  | static DWORD WINAPI download_proc(PVOID arg) | 
|  | { | 
|  | IMoniker *mon; | 
|  | IBindCtx *bctx; | 
|  | IStream *str = NULL; | 
|  | HRESULT hres; | 
|  |  | 
|  | CreateURLMoniker(NULL, url, &mon); | 
|  | mshtml_free(url); | 
|  | url = NULL; | 
|  |  | 
|  | CreateAsyncBindCtx(0, &InstallCallback, 0, &bctx); | 
|  |  | 
|  | hres = IMoniker_BindToStorage(mon, bctx, NULL, &IID_IStream, (void**)&str); | 
|  | IBindCtx_Release(bctx); | 
|  | if(FAILED(hres)) { | 
|  | ERR("BindToStorage failed: %08x\n", hres); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if(str) | 
|  | IStream_Release(str); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static INT_PTR CALLBACK installer_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) | 
|  | { | 
|  | switch(msg) { | 
|  | case WM_INITDIALOG: | 
|  | install_dialog = hwnd; | 
|  | return TRUE; | 
|  |  | 
|  | case WM_COMMAND: | 
|  | switch(wParam) { | 
|  | case IDCANCEL: | 
|  | EndDialog(hwnd, 0); | 
|  | return FALSE; | 
|  |  | 
|  | case ID_DWL_INSTALL: | 
|  | EnableWindow(GetDlgItem(hwnd, ID_DWL_INSTALL), 0); | 
|  | EnableWindow(GetDlgItem(hwnd, IDCANCEL), 0); /* FIXME */ | 
|  | CreateThread(NULL, 0, download_proc, NULL, 0, NULL); | 
|  | return FALSE; | 
|  | } | 
|  | } | 
|  |  | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | void install_wine_gecko(void) | 
|  | { | 
|  | HANDLE hsem; | 
|  |  | 
|  | SetLastError(ERROR_SUCCESS); | 
|  | hsem = CreateSemaphoreA( NULL, 0, 1, "mshtml_install_semaphore"); | 
|  |  | 
|  | if(GetLastError() == ERROR_ALREADY_EXISTS) { | 
|  | WaitForSingleObject(hsem, INFINITE); | 
|  | }else { | 
|  | if((url = get_url())) | 
|  | DialogBoxW(hInst, MAKEINTRESOURCEW(ID_DWL_DIALOG), 0, installer_proc); | 
|  | } | 
|  |  | 
|  | ReleaseSemaphore(hsem, 1, NULL); | 
|  | CloseHandle(hsem); | 
|  | } |