/* * ieframe - Internet Explorer main frame window * * Copyright 2006 Mike McCormack (for CodeWeavers) * 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 */ #define COBJMACROS #include <stdarg.h> #include "ieframe.h" #include "resource.h" #include "winuser.h" #include "wingdi.h" #include "winnls.h" #include "ole2.h" #include "exdisp.h" #include "oleidl.h" #include "mshtmcid.h" #include "shellapi.h" #include "winreg.h" #include "shlwapi.h" #include "intshcut.h" #include "ddeml.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(ieframe); #define IDI_APPICON 1 #define WM_UPDATEADDRBAR (WM_APP+1) static const WCHAR szIEWinFrame[] = { 'I','E','F','r','a','m','e',0 }; /* Windows uses "Microsoft Internet Explorer" */ static const WCHAR wszWineInternetExplorer[] = {'W','i','n','e',' ','I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r',0}; static LONG obj_cnt; static DWORD dde_inst; static HSZ ddestr_iexplore, ddestr_openurl; static struct list ie_list = LIST_INIT(ie_list); HRESULT update_ie_statustext(InternetExplorer* This, LPCWSTR text) { if(!SendMessageW(This->status_hwnd, SB_SETTEXTW, MAKEWORD(SB_SIMPLEID, 0), (LPARAM)text)) return E_FAIL; return S_OK; } static void adjust_ie_docobj_rect(HWND frame, RECT* rc) { HWND hwndRebar = GetDlgItem(frame, IDC_BROWSE_REBAR); HWND hwndStatus = GetDlgItem(frame, IDC_BROWSE_STATUSBAR); INT barHeight = SendMessageW(hwndRebar, RB_GETBARHEIGHT, 0, 0); rc->top += barHeight; rc->bottom -= barHeight; if(IsWindowVisible(hwndStatus)) { RECT statusrc; GetClientRect(hwndStatus, &statusrc); rc->bottom -= statusrc.bottom - statusrc.top; } } static HMENU get_tb_menu(HMENU menu) { HMENU menu_view = GetSubMenu(menu, 1); return GetSubMenu(menu_view, 0); } static HMENU get_fav_menu(HMENU menu) { return GetSubMenu(menu, 2); } static LPWSTR get_fav_url_from_id(HMENU menu, UINT id) { MENUITEMINFOW item; item.cbSize = sizeof(item); item.fMask = MIIM_DATA; if(!GetMenuItemInfoW(menu, id, FALSE, &item)) return NULL; return (LPWSTR)item.dwItemData; } static void free_fav_menu_data(HMENU menu) { LPWSTR url; int i; for(i = 0; (url = get_fav_url_from_id(menu, ID_BROWSE_GOTOFAV_FIRST + i)); i++) heap_free( url ); } static int get_menu_item_count(HMENU menu) { MENUITEMINFOW item; int count = 0; int i; item.cbSize = sizeof(item); item.fMask = MIIM_DATA | MIIM_SUBMENU; for(i = 0; GetMenuItemInfoW(menu, i, TRUE, &item); i++) { if(item.hSubMenu) count += get_menu_item_count(item.hSubMenu); else count++; } return count; } static void add_fav_to_menu(HMENU favmenu, HMENU menu, LPWSTR title, LPCWSTR url) { MENUITEMINFOW item; /* Subtract the number of standard elements in the Favorites menu */ int favcount = get_menu_item_count(favmenu) - 2; LPWSTR urlbuf; if(favcount > (ID_BROWSE_GOTOFAV_MAX - ID_BROWSE_GOTOFAV_FIRST)) { FIXME("Add support for more than %d Favorites\n", favcount); return; } urlbuf = heap_alloc((lstrlenW(url) + 1) * sizeof(WCHAR)); if(!urlbuf) return; lstrcpyW(urlbuf, url); item.cbSize = sizeof(item); item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA | MIIM_ID; item.fType = MFT_STRING; item.dwTypeData = title; item.wID = ID_BROWSE_GOTOFAV_FIRST + favcount; item.dwItemData = (ULONG_PTR)urlbuf; InsertMenuItemW(menu, -1, TRUE, &item); } static void add_favs_to_menu(HMENU favmenu, HMENU menu, LPCWSTR dir) { WCHAR path[MAX_PATH*2]; const WCHAR search[] = {'*',0}; WCHAR* filename; HANDLE findhandle; WIN32_FIND_DATAW finddata; IUniformResourceLocatorW* urlobj; IPersistFile* urlfile = NULL; HRESULT res; lstrcpyW(path, dir); PathAppendW(path, search); findhandle = FindFirstFileW(path, &finddata); if(findhandle == INVALID_HANDLE_VALUE) return; res = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER, &IID_IUniformResourceLocatorW, (PVOID*)&urlobj); if(SUCCEEDED(res)) res = IUnknown_QueryInterface(urlobj, &IID_IPersistFile, (PVOID*)&urlfile); if(SUCCEEDED(res)) { filename = path + lstrlenW(path) - lstrlenW(search); do { lstrcpyW(filename, finddata.cFileName); if(finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { MENUITEMINFOW item; const WCHAR ignore1[] = {'.','.',0}; const WCHAR ignore2[] = {'.',0}; if(!lstrcmpW(filename, ignore1) || !lstrcmpW(filename, ignore2)) continue; item.cbSize = sizeof(item); item.fMask = MIIM_STRING | MIIM_SUBMENU; item.dwTypeData = filename; item.hSubMenu = CreatePopupMenu(); InsertMenuItemW(menu, -1, TRUE, &item); add_favs_to_menu(favmenu, item.hSubMenu, path); } else { WCHAR* fileext; WCHAR* url = NULL; const WCHAR urlext[] = {'.','u','r','l',0}; if(lstrcmpiW(PathFindExtensionW(filename), urlext)) continue; if(FAILED(IPersistFile_Load(urlfile, path, 0))) continue; urlobj->lpVtbl->GetURL(urlobj, &url); if(!url) continue; fileext = filename + lstrlenW(filename) - lstrlenW(urlext); *fileext = 0; add_fav_to_menu(favmenu, menu, filename, url); } } while(FindNextFileW(findhandle, &finddata)); } if(urlfile) IPersistFile_Release(urlfile); if(urlobj) IUnknown_Release(urlobj); FindClose(findhandle); } static void add_tbs_to_menu(HMENU menu) { HUSKEY toolbar_handle; WCHAR toolbar_key[] = {'S','o','f','t','w','a','r','e','\\', 'M','i','c','r','o','s','o','f','t','\\', 'I','n','t','e','r','n','e','t',' ', 'E','x','p','l','o','r','e','r','\\', 'T','o','o','l','b','a','r',0}; if(SHRegOpenUSKeyW(toolbar_key, KEY_READ, NULL, &toolbar_handle, TRUE) == ERROR_SUCCESS) { HUSKEY classes_handle; WCHAR classes_key[] = {'S','o','f','t','w','a','r','e','\\', 'C','l','a','s','s','e','s','\\','C','L','S','I','D',0}; WCHAR guid[39]; DWORD value_len = sizeof(guid)/sizeof(guid[0]); int i; if(SHRegOpenUSKeyW(classes_key, KEY_READ, NULL, &classes_handle, TRUE) != ERROR_SUCCESS) { SHRegCloseUSKey(toolbar_handle); ERR("Failed to open key %s\n", debugstr_w(classes_key)); return; } for(i = 0; SHRegEnumUSValueW(toolbar_handle, i, guid, &value_len, NULL, NULL, NULL, SHREGENUM_HKLM) == ERROR_SUCCESS; i++) { WCHAR tb_name[100]; DWORD tb_name_len = sizeof(tb_name)/sizeof(tb_name[0]); HUSKEY tb_class_handle; MENUITEMINFOW item; LSTATUS ret; value_len = sizeof(guid)/sizeof(guid[0]); if(lstrlenW(guid) != 38) { TRACE("Found invalid IE toolbar entry: %s\n", debugstr_w(guid)); continue; } if(SHRegOpenUSKeyW(guid, KEY_READ, classes_handle, &tb_class_handle, TRUE) != ERROR_SUCCESS) { ERR("Failed to get class info for %s\n", debugstr_w(guid)); continue; } ret = SHRegQueryUSValueW(tb_class_handle, NULL, NULL, tb_name, &tb_name_len, TRUE, NULL, 0); SHRegCloseUSKey(tb_class_handle); if(ret != ERROR_SUCCESS) { ERR("Failed to get toolbar name for %s\n", debugstr_w(guid)); continue; } item.cbSize = sizeof(item); item.fMask = MIIM_STRING; item.dwTypeData = tb_name; InsertMenuItemW(menu, GetMenuItemCount(menu), TRUE, &item); } SHRegCloseUSKey(classes_handle); SHRegCloseUSKey(toolbar_handle); } } static HMENU create_ie_menu(void) { HMENU menu = LoadMenuW(ieframe_instance, MAKEINTRESOURCEW(IDR_BROWSE_MAIN_MENU)); HMENU favmenu = get_fav_menu(menu); WCHAR path[MAX_PATH]; add_tbs_to_menu(get_tb_menu(menu)); if(SHGetFolderPathW(NULL, CSIDL_COMMON_FAVORITES, NULL, SHGFP_TYPE_CURRENT, path) == S_OK) add_favs_to_menu(favmenu, favmenu, path); if(SHGetFolderPathW(NULL, CSIDL_FAVORITES, NULL, SHGFP_TYPE_CURRENT, path) == S_OK) add_favs_to_menu(favmenu, favmenu, path); return menu; } static void ie_navigate(InternetExplorer* This, LPCWSTR url) { VARIANT variant; V_VT(&variant) = VT_BSTR; V_BSTR(&variant) = SysAllocString(url); IWebBrowser2_Navigate2(&This->IWebBrowser2_iface, &variant, NULL, NULL, NULL, NULL); SysFreeString(V_BSTR(&variant)); } static INT_PTR CALLBACK ie_dialog_open_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { static InternetExplorer* This; switch(msg) { case WM_INITDIALOG: This = (InternetExplorer*)lparam; EnableWindow(GetDlgItem(hwnd, IDOK), FALSE); return TRUE; case WM_COMMAND: switch(LOWORD(wparam)) { case IDC_BROWSE_OPEN_URL: { HWND hwndurl = GetDlgItem(hwnd, IDC_BROWSE_OPEN_URL); int len = GetWindowTextLengthW(hwndurl); EnableWindow(GetDlgItem(hwnd, IDOK), len ? TRUE : FALSE); break; } case IDOK: { HWND hwndurl = GetDlgItem(hwnd, IDC_BROWSE_OPEN_URL); int len = GetWindowTextLengthW(hwndurl); if(len) { VARIANT url; V_VT(&url) = VT_BSTR; V_BSTR(&url) = SysAllocStringLen(NULL, len); GetWindowTextW(hwndurl, V_BSTR(&url), len + 1); IWebBrowser2_Navigate2(&This->IWebBrowser2_iface, &url, NULL, NULL, NULL, NULL); SysFreeString(V_BSTR(&url)); } } /* fall through */ case IDCANCEL: EndDialog(hwnd, wparam); return TRUE; } } return FALSE; } static void ie_dialog_about(HWND hwnd) { HICON icon = LoadImageW(GetModuleHandleW(0), MAKEINTRESOURCEW(IDI_APPICON), IMAGE_ICON, 48, 48, LR_SHARED); ShellAboutW(hwnd, wszWineInternetExplorer, NULL, icon); DestroyIcon(icon); } static void add_tb_separator(HWND hwnd) { TBBUTTON btn; ZeroMemory(&btn, sizeof(btn)); btn.iBitmap = 3; btn.fsStyle = BTNS_SEP; SendMessageW(hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&btn); } static void add_tb_button(HWND hwnd, int bmp, int cmd, int strId) { TBBUTTON btn; WCHAR buf[30]; LoadStringW(ieframe_instance, strId, buf, sizeof(buf)/sizeof(buf[0])); btn.iBitmap = bmp; btn.idCommand = cmd; btn.fsState = TBSTATE_ENABLED; btn.fsStyle = BTNS_SHOWTEXT; btn.dwData = 0; btn.iString = (INT_PTR)buf; SendMessageW(hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&btn); } static void create_rebar(HWND hwnd) { HWND hwndRebar; HWND hwndAddress; HWND hwndToolbar; REBARINFO rebarinf; REBARBANDINFOW bandinf; WCHAR addr[40]; HIMAGELIST imagelist; WCHAR idb_ietoolbar[] = {'I','D','B','_','I','E','T','O','O','L','B','A','R',0}; LoadStringW(ieframe_instance, IDS_ADDRESS, addr, sizeof(addr)/sizeof(addr[0])); hwndRebar = CreateWindowExW(WS_EX_TOOLWINDOW, REBARCLASSNAMEW, NULL, WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|RBS_VARHEIGHT|CCS_TOP|CCS_NODIVIDER, 0, 0, 0, 0, hwnd, (HMENU)IDC_BROWSE_REBAR, ieframe_instance, NULL); rebarinf.cbSize = sizeof(rebarinf); rebarinf.fMask = 0; rebarinf.himl = NULL; rebarinf.cbSize = sizeof(rebarinf); SendMessageW(hwndRebar, RB_SETBARINFO, 0, (LPARAM)&rebarinf); hwndToolbar = CreateWindowExW(TBSTYLE_EX_MIXEDBUTTONS, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hwndRebar, (HMENU)IDC_BROWSE_TOOLBAR, ieframe_instance, NULL); imagelist = ImageList_LoadImageW(ieframe_instance, idb_ietoolbar, 32, 0, CLR_NONE, IMAGE_BITMAP, LR_CREATEDIBSECTION); SendMessageW(hwndToolbar, TB_SETIMAGELIST, 0, (LPARAM)imagelist); SendMessageW(hwndToolbar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0); add_tb_button(hwndToolbar, 0, ID_BROWSE_BACK, IDS_TB_BACK); add_tb_button(hwndToolbar, 1, ID_BROWSE_FORWARD, IDS_TB_FORWARD); add_tb_button(hwndToolbar, 2, ID_BROWSE_STOP, IDS_TB_STOP); add_tb_button(hwndToolbar, 3, ID_BROWSE_REFRESH, IDS_TB_REFRESH); add_tb_button(hwndToolbar, 4, ID_BROWSE_HOME, IDS_TB_HOME); add_tb_separator(hwndToolbar); add_tb_button(hwndToolbar, 5, ID_BROWSE_PRINT, IDS_TB_PRINT); SendMessageW(hwndToolbar, TB_SETBUTTONSIZE, 0, MAKELPARAM(55,50)); SendMessageW(hwndToolbar, TB_AUTOSIZE, 0, 0); bandinf.cbSize = sizeof(bandinf); bandinf.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE; bandinf.fStyle = RBBS_CHILDEDGE; bandinf.cx = 100; bandinf.cyMinChild = 52; bandinf.hwndChild = hwndToolbar; SendMessageW(hwndRebar, RB_INSERTBANDW, -1, (LPARAM)&bandinf); hwndAddress = CreateWindowExW(0, WC_COMBOBOXEXW, NULL, WS_BORDER|WS_CHILD|WS_VISIBLE|CBS_DROPDOWN, 0, 0, 100,20,hwndRebar, (HMENU)IDC_BROWSE_ADDRESSBAR, ieframe_instance, NULL); bandinf.fMask |= RBBIM_TEXT; bandinf.fStyle = RBBS_CHILDEDGE | RBBS_BREAK; bandinf.lpText = addr; bandinf.cyMinChild = 20; bandinf.hwndChild = hwndAddress; SendMessageW(hwndRebar, RB_INSERTBANDW, -1, (LPARAM)&bandinf); } static LRESULT iewnd_OnCreate(HWND hwnd, LPCREATESTRUCTW lpcs) { InternetExplorer* This = (InternetExplorer*)lpcs->lpCreateParams; SetWindowLongPtrW(hwnd, 0, (LONG_PTR) lpcs->lpCreateParams); This->menu = create_ie_menu(); This->status_hwnd = CreateStatusWindowW(WS_VISIBLE|WS_CHILD|SBT_NOBORDERS|CCS_NODIVIDER, NULL, hwnd, IDC_BROWSE_STATUSBAR); SendMessageW(This->status_hwnd, SB_SIMPLE, TRUE, 0); create_rebar(hwnd); return 0; } static LRESULT iewnd_OnSize(InternetExplorer *This, INT width, INT height) { HWND hwndRebar = GetDlgItem(This->frame_hwnd, IDC_BROWSE_REBAR); INT barHeight = SendMessageW(hwndRebar, RB_GETBARHEIGHT, 0, 0); RECT docarea = {0, 0, width, height}; SendMessageW(This->status_hwnd, WM_SIZE, 0, 0); adjust_ie_docobj_rect(This->frame_hwnd, &docarea); if(This->doc_host->doc_host.hwnd) SetWindowPos(This->doc_host->doc_host.hwnd, NULL, docarea.left, docarea.top, docarea.right, docarea.bottom, SWP_NOZORDER | SWP_NOACTIVATE); SetWindowPos(hwndRebar, NULL, 0, 0, width, barHeight, SWP_NOZORDER | SWP_NOACTIVATE); return 0; } static LRESULT iewnd_OnNotify(InternetExplorer *This, WPARAM wparam, LPARAM lparam) { NMHDR* hdr = (NMHDR*)lparam; if(hdr->idFrom == IDC_BROWSE_ADDRESSBAR && hdr->code == CBEN_ENDEDITW) { NMCBEENDEDITW* info = (NMCBEENDEDITW*)lparam; if(info->fChanged && info->iWhy == CBENF_RETURN) { VARIANT vt; V_VT(&vt) = VT_BSTR; V_BSTR(&vt) = SysAllocString(info->szText); IWebBrowser2_Navigate2(&This->IWebBrowser2_iface, &vt, NULL, NULL, NULL, NULL); SysFreeString(V_BSTR(&vt)); return 0; } } return 0; } static LRESULT iewnd_OnDestroy(InternetExplorer *This) { HWND hwndRebar = GetDlgItem(This->frame_hwnd, IDC_BROWSE_REBAR); HWND hwndToolbar = GetDlgItem(hwndRebar, IDC_BROWSE_TOOLBAR); HIMAGELIST list = (HIMAGELIST)SendMessageW(hwndToolbar, TB_GETIMAGELIST, 0, 0); TRACE("%p\n", This); free_fav_menu_data(get_fav_menu(This->menu)); ImageList_Destroy(list); This->frame_hwnd = NULL; return 0; } static LRESULT iewnd_OnCommand(InternetExplorer *This, HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { switch(LOWORD(wparam)) { case ID_BROWSE_OPEN: DialogBoxParamW(ieframe_instance, MAKEINTRESOURCEW(IDD_BROWSE_OPEN), hwnd, ie_dialog_open_proc, (LPARAM)This); break; case ID_BROWSE_PRINT: if(This->doc_host->doc_host.document) { IOleCommandTarget* target; if(FAILED(IUnknown_QueryInterface(This->doc_host->doc_host.document, &IID_IOleCommandTarget, (LPVOID*)&target))) break; IOleCommandTarget_Exec(target, &CGID_MSHTML, IDM_PRINT, OLECMDEXECOPT_DODEFAULT, NULL, NULL); IOleCommandTarget_Release(target); } break; case ID_BROWSE_HOME: IWebBrowser2_GoHome(&This->IWebBrowser2_iface); break; case ID_BROWSE_BACK: IWebBrowser2_GoBack(&This->IWebBrowser2_iface); break; case ID_BROWSE_FORWARD: IWebBrowser2_GoForward(&This->IWebBrowser2_iface); break; case ID_BROWSE_STOP: IWebBrowser2_Stop(&This->IWebBrowser2_iface); break; case ID_BROWSE_REFRESH: IWebBrowser2_Refresh(&This->IWebBrowser2_iface); break; case ID_BROWSE_ABOUT: ie_dialog_about(hwnd); break; case ID_BROWSE_QUIT: ShowWindow(hwnd, SW_HIDE); break; default: if(LOWORD(wparam) >= ID_BROWSE_GOTOFAV_FIRST && LOWORD(wparam) <= ID_BROWSE_GOTOFAV_MAX) { LPCWSTR url = get_fav_url_from_id(get_fav_menu(This->menu), LOWORD(wparam)); if(url) ie_navigate(This, url); } return DefWindowProcW(hwnd, msg, wparam, lparam); } return 0; } static LRESULT update_addrbar(InternetExplorer *This, LPARAM lparam) { HWND hwndRebar = GetDlgItem(This->frame_hwnd, IDC_BROWSE_REBAR); HWND hwndAddress = GetDlgItem(hwndRebar, IDC_BROWSE_ADDRESSBAR); HWND hwndEdit = (HWND)SendMessageW(hwndAddress, CBEM_GETEDITCONTROL, 0, 0); LPCWSTR url = (LPCWSTR)lparam; SendMessageW(hwndEdit, WM_SETTEXT, 0, (LPARAM)url); return 0; } static LRESULT WINAPI ie_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { InternetExplorer *This = (InternetExplorer*) GetWindowLongPtrW(hwnd, 0); switch (msg) { case WM_CREATE: return iewnd_OnCreate(hwnd, (LPCREATESTRUCTW)lparam); case WM_CLOSE: TRACE("WM_CLOSE\n"); ShowWindow(hwnd, SW_HIDE); return 0; case WM_SHOWWINDOW: TRACE("WM_SHOWWINDOW %lx\n", wparam); if(wparam) IWebBrowser2_AddRef(&This->IWebBrowser2_iface); else IWebBrowser2_Release(&This->IWebBrowser2_iface); break; case WM_DESTROY: return iewnd_OnDestroy(This); case WM_SIZE: return iewnd_OnSize(This, LOWORD(lparam), HIWORD(lparam)); case WM_COMMAND: return iewnd_OnCommand(This, hwnd, msg, wparam, lparam); case WM_NOTIFY: return iewnd_OnNotify(This, wparam, lparam); case WM_DOCHOSTTASK: return process_dochost_tasks(&This->doc_host->doc_host); case WM_UPDATEADDRBAR: return update_addrbar(This, lparam); } return DefWindowProcW(hwnd, msg, wparam, lparam); } void register_iewindow_class(void) { WNDCLASSEXW wc; memset(&wc, 0, sizeof wc); wc.cbSize = sizeof(wc); wc.style = 0; wc.lpfnWndProc = ie_window_proc; wc.cbClsExtra = 0; wc.cbWndExtra = sizeof(InternetExplorer*); wc.hInstance = ieframe_instance; wc.hIcon = LoadIconW(GetModuleHandleW(0), MAKEINTRESOURCEW(IDI_APPICON)); wc.hIconSm = LoadImageW(GetModuleHandleW(0), MAKEINTRESOURCEW(IDI_APPICON), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); wc.hCursor = LoadCursorW(0, MAKEINTRESOURCEW(IDC_ARROW)); wc.hbrBackground = 0; wc.lpszClassName = szIEWinFrame; wc.lpszMenuName = NULL; RegisterClassExW(&wc); } void unregister_iewindow_class(void) { UnregisterClassW(szIEWinFrame, ieframe_instance); } static void create_frame_hwnd(InternetExplorer *This) { This->frame_hwnd = CreateWindowExW( WS_EX_WINDOWEDGE, szIEWinFrame, wszWineInternetExplorer, WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL /* FIXME */, ieframe_instance, This); This->doc_host->doc_host.frame_hwnd = This->frame_hwnd; create_doc_view_hwnd(&This->doc_host->doc_host); } static inline IEDocHost *impl_from_DocHost(DocHost *iface) { return CONTAINING_RECORD(iface, IEDocHost, doc_host); } static ULONG IEDocHost_addref(DocHost *iface) { IEDocHost *This = impl_from_DocHost(iface); LONG ref = InterlockedIncrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); return ref; } static ULONG IEDocHost_release(DocHost *iface) { IEDocHost *This = impl_from_DocHost(iface); LONG ref = InterlockedDecrement(&This->ref); TRACE("(%p) ref=%d\n", This, ref); if(!ref) { if(This->ie) ERR("This->ie is not NULL\n"); heap_free(This); } return ref; } static void WINAPI DocHostContainer_GetDocObjRect(DocHost* This, RECT* rc) { GetClientRect(This->frame_hwnd, rc); adjust_ie_docobj_rect(This->frame_hwnd, rc); } static HRESULT WINAPI DocHostContainer_SetStatusText(DocHost *iface, LPCWSTR text) { IEDocHost *This = impl_from_DocHost(iface); return update_ie_statustext(This->ie, text); } static void WINAPI DocHostContainer_SetURL(DocHost* iface, LPCWSTR url) { IEDocHost *This = impl_from_DocHost(iface); if(!This->ie) return; This->ie->nohome = FALSE; SendMessageW(This->ie->frame_hwnd, WM_UPDATEADDRBAR, 0, (LPARAM)url); } static HRESULT DocHostContainer_exec(DocHost* This, const GUID *cmd_group, DWORD cmdid, DWORD execopt, VARIANT *in, VARIANT *out) { return S_OK; } static const IDocHostContainerVtbl DocHostContainerVtbl = { IEDocHost_addref, IEDocHost_release, DocHostContainer_GetDocObjRect, DocHostContainer_SetStatusText, DocHostContainer_SetURL, DocHostContainer_exec }; static HRESULT create_ie(InternetExplorer **ret_obj) { InternetExplorer *ret; ret = heap_alloc_zero(sizeof(InternetExplorer)); if(!ret) return E_OUTOFMEMORY; ret->doc_host = heap_alloc_zero(sizeof(IEDocHost)); if(!ret->doc_host) { heap_free(ret); return E_OUTOFMEMORY; } ret->ref = 1; ret->doc_host->ref = 1; ret->doc_host->ie = ret; DocHost_Init(&ret->doc_host->doc_host, &ret->IWebBrowser2_iface, &DocHostContainerVtbl); InternetExplorer_WebBrowser_Init(ret); HlinkFrame_Init(&ret->hlink_frame, (IUnknown*)&ret->IWebBrowser2_iface, &ret->doc_host->doc_host); create_frame_hwnd(ret); InterlockedIncrement(&obj_cnt); list_add_tail(&ie_list, &ret->entry); *ret_obj = ret; return S_OK; } HRESULT WINAPI InternetExplorer_Create(IClassFactory *iface, IUnknown *pOuter, REFIID riid, void **ppv) { InternetExplorer *ret; HRESULT hres; TRACE("(%p %s %p)\n", pOuter, debugstr_guid(riid), ppv); hres = create_ie(&ret); if(FAILED(hres)) return hres; hres = IWebBrowser2_QueryInterface(&ret->IWebBrowser2_iface, riid, ppv); IWebBrowser2_Release(&ret->IWebBrowser2_iface); if(FAILED(hres)) return hres; return S_OK; } void released_obj(void) { if(!InterlockedDecrement(&obj_cnt)) PostQuitMessage(0); } static BOOL create_ie_window(const WCHAR *cmdline) { InternetExplorer *ie; HRESULT hres; hres = create_ie(&ie); if(FAILED(hres)) return FALSE; IWebBrowser2_put_Visible(&ie->IWebBrowser2_iface, VARIANT_TRUE); IWebBrowser2_put_MenuBar(&ie->IWebBrowser2_iface, VARIANT_TRUE); if(!*cmdline) { IWebBrowser2_GoHome(&ie->IWebBrowser2_iface); }else { VARIANT var_url; int cmdlen; static const WCHAR nohomeW[] = {'-','n','o','h','o','m','e'}; while(*cmdline == ' ' || *cmdline == '\t') cmdline++; cmdlen = strlenW(cmdline); if(cmdlen > 2 && cmdline[0] == '"' && cmdline[cmdlen-1] == '"') { cmdline++; cmdlen -= 2; } if(cmdlen == sizeof(nohomeW)/sizeof(*nohomeW) && !memcmp(cmdline, nohomeW, sizeof(nohomeW))) { ie->nohome = TRUE; }else { V_VT(&var_url) = VT_BSTR; V_BSTR(&var_url) = SysAllocStringLen(cmdline, cmdlen); /* navigate to the first page */ IWebBrowser2_Navigate2(&ie->IWebBrowser2_iface, &var_url, NULL, NULL, NULL, NULL); SysFreeString(V_BSTR(&var_url)); } } IWebBrowser2_Release(&ie->IWebBrowser2_iface); return TRUE; } static HDDEDATA open_dde_url(WCHAR *dde_url) { InternetExplorer *ie = NULL, *iter; WCHAR *url, *url_end; VARIANT urlv; HRESULT hres; TRACE("%s\n", debugstr_w(dde_url)); url = dde_url; if(*url == '"') { url++; url_end = strchrW(url, '"'); if(!url_end) { FIXME("missing string terminator\n"); return 0; } *url_end = 0; }else { url_end = strchrW(url, ','); if(url_end) *url_end = 0; else url_end = url + strlenW(url); } LIST_FOR_EACH_ENTRY(iter, &ie_list, InternetExplorer, entry) { if(iter->nohome) { IWebBrowser2_AddRef(&iter->IWebBrowser2_iface); ie = iter; break; } } if(!ie) { hres = create_ie(&ie); if(FAILED(hres)) return 0; } IWebBrowser2_put_Visible(&ie->IWebBrowser2_iface, VARIANT_TRUE); IWebBrowser2_put_MenuBar(&ie->IWebBrowser2_iface, VARIANT_TRUE); V_VT(&urlv) = VT_BSTR; V_BSTR(&urlv) = SysAllocStringLen(url, url_end-url); if(!V_BSTR(&urlv)) { IWebBrowser2_Release(&ie->IWebBrowser2_iface); return 0; } hres = IWebBrowser2_Navigate2(&ie->IWebBrowser2_iface, &urlv, NULL, NULL, NULL, NULL); if(FAILED(hres)) return 0; IWebBrowser2_Release(&ie->IWebBrowser2_iface); return ULongToHandle(DDE_FACK); } static HDDEDATA WINAPI dde_proc(UINT type, UINT uFmt, HCONV hConv, HSZ hsz1, HSZ hsz2, HDDEDATA data, ULONG_PTR dwData1, ULONG_PTR dwData2) { switch(type) { case XTYP_CONNECT: TRACE("XTYP_CONNECT %p\n", hsz1); return ULongToHandle(!DdeCmpStringHandles(hsz1, ddestr_openurl)); case XTYP_EXECUTE: { WCHAR *url; DWORD size; HDDEDATA ret; TRACE("XTYP_EXECUTE %p\n", data); size = DdeGetData(data, NULL, 0, 0); if(!size) { WARN("size = 0\n"); break; } url = heap_alloc(size); if(!url) break; if(DdeGetData(data, (BYTE*)url, size, 0) != size) { ERR("error during read\n"); break; } ret = open_dde_url(url); heap_free(url); return ret; } case XTYP_REQUEST: FIXME("XTYP_REQUEST\n"); break; default: TRACE("type %d\n", type); } return NULL; } static void init_dde(void) { UINT res; static const WCHAR iexploreW[] = {'I','E','x','p','l','o','r','e',0}; static const WCHAR openurlW[] = {'W','W','W','_','O','p','e','n','U','R','L',0}; res = DdeInitializeW(&dde_inst, dde_proc, CBF_SKIP_ALLNOTIFICATIONS | CBF_FAIL_ADVISES | CBF_FAIL_POKES, 0); if(res != DMLERR_NO_ERROR) { WARN("DdeInitialize failed: %u\n", res); return; } ddestr_iexplore = DdeCreateStringHandleW(dde_inst, iexploreW, CP_WINUNICODE); if(!ddestr_iexplore) WARN("Failed to create string handle: %u\n", DdeGetLastError(dde_inst)); ddestr_openurl = DdeCreateStringHandleW(dde_inst, openurlW, CP_WINUNICODE); if(!ddestr_openurl) WARN("Failed to create string handle: %u\n", DdeGetLastError(dde_inst)); res = HandleToULong(DdeNameService(dde_inst, ddestr_iexplore, 0, DNS_REGISTER)); if(res != DMLERR_NO_ERROR) WARN("DdeNameService failed: %u\n", res); } static void release_dde(void) { if(ddestr_iexplore) DdeNameService(dde_inst, ddestr_iexplore, 0, DNS_UNREGISTER); if(ddestr_openurl) DdeFreeStringHandle(dde_inst, ddestr_openurl); if(ddestr_iexplore) DdeFreeStringHandle(dde_inst, ddestr_iexplore); DdeUninitialize(dde_inst); } /****************************************************************** * IEWinMain (ieframe.101) * * Only returns on error. */ DWORD WINAPI IEWinMain(const WCHAR *cmdline, int nShowWindow) { MSG msg; HRESULT hres; static const WCHAR embeddingW[] = {'-','e','m','b','e','d','d','i','n','g',0}; TRACE("%s %d\n", debugstr_w(cmdline), nShowWindow); CoInitialize(NULL); hres = register_class_object(TRUE); if(FAILED(hres)) { CoUninitialize(); ExitProcess(1); } init_dde(); if(strcmpiW(cmdline, embeddingW)) { if(!create_ie_window(cmdline)) { CoUninitialize(); ExitProcess(1); } } /* run the message loop for this thread */ while (GetMessageW(&msg, 0, 0, 0)) { TranslateMessage(&msg); DispatchMessageW(&msg); } register_class_object(FALSE); release_dde(); CoUninitialize(); ExitProcess(0); return 0; }