06c86b4b697a66aca9036057a4c0a62b8398a003
[reactos.git] / reactos / dll / win32 / ieframe / iexplore.c
1 /*
2 * ieframe - Internet Explorer main frame window
3 *
4 * Copyright 2006 Mike McCormack (for CodeWeavers)
5 * Copyright 2006 Jacek Caban (for CodeWeavers)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "ieframe.h"
23
24 #include <mshtmcid.h>
25 #include <ddeml.h>
26
27 #define IDI_APPICON 1
28
29 #define WM_UPDATEADDRBAR (WM_APP+1)
30
31 static const WCHAR szIEWinFrame[] = { 'I','E','F','r','a','m','e',0 };
32
33 /* Windows uses "Microsoft Internet Explorer" */
34 static const WCHAR wszWineInternetExplorer[] =
35 {'W','i','n','e',' ','I','n','t','e','r','n','e','t',' ','E','x','p','l','o','r','e','r',0};
36
37 static LONG obj_cnt;
38 static DWORD dde_inst;
39 static HSZ ddestr_iexplore, ddestr_openurl;
40 static struct list ie_list = LIST_INIT(ie_list);
41
42 HRESULT update_ie_statustext(InternetExplorer* This, LPCWSTR text)
43 {
44 if(!SendMessageW(This->status_hwnd, SB_SETTEXTW, MAKEWORD(SB_SIMPLEID, 0), (LPARAM)text))
45 return E_FAIL;
46
47 return S_OK;
48 }
49
50 static void adjust_ie_docobj_rect(HWND frame, RECT* rc)
51 {
52 HWND hwndRebar = GetDlgItem(frame, IDC_BROWSE_REBAR);
53 HWND hwndStatus = GetDlgItem(frame, IDC_BROWSE_STATUSBAR);
54 INT barHeight = SendMessageW(hwndRebar, RB_GETBARHEIGHT, 0, 0);
55
56 rc->top += barHeight;
57 rc->bottom -= barHeight;
58
59 if(IsWindowVisible(hwndStatus))
60 {
61 RECT statusrc;
62
63 GetClientRect(hwndStatus, &statusrc);
64 rc->bottom -= statusrc.bottom - statusrc.top;
65 }
66 }
67
68 static HMENU get_tb_menu(HMENU menu)
69 {
70 HMENU menu_view = GetSubMenu(menu, 1);
71
72 return GetSubMenu(menu_view, 0);
73 }
74
75 static HMENU get_fav_menu(HMENU menu)
76 {
77 return GetSubMenu(menu, 2);
78 }
79
80 static LPWSTR get_fav_url_from_id(HMENU menu, UINT id)
81 {
82 MENUITEMINFOW item;
83
84 item.cbSize = sizeof(item);
85 item.fMask = MIIM_DATA;
86
87 if(!GetMenuItemInfoW(menu, id, FALSE, &item))
88 return NULL;
89
90 return (LPWSTR)item.dwItemData;
91 }
92
93 static void free_fav_menu_data(HMENU menu)
94 {
95 LPWSTR url;
96 int i;
97
98 for(i = 0; (url = get_fav_url_from_id(menu, ID_BROWSE_GOTOFAV_FIRST + i)); i++)
99 heap_free( url );
100 }
101
102 static int get_menu_item_count(HMENU menu)
103 {
104 MENUITEMINFOW item;
105 int count = 0;
106 int i;
107
108 item.cbSize = sizeof(item);
109 item.fMask = MIIM_DATA | MIIM_SUBMENU;
110
111 for(i = 0; GetMenuItemInfoW(menu, i, TRUE, &item); i++)
112 {
113 if(item.hSubMenu)
114 count += get_menu_item_count(item.hSubMenu);
115 else
116 count++;
117 }
118
119 return count;
120 }
121
122 static void add_fav_to_menu(HMENU favmenu, HMENU menu, LPWSTR title, LPCWSTR url)
123 {
124 MENUITEMINFOW item;
125 /* Subtract the number of standard elements in the Favorites menu */
126 int favcount = get_menu_item_count(favmenu) - 2;
127 LPWSTR urlbuf;
128
129 if(favcount > (ID_BROWSE_GOTOFAV_MAX - ID_BROWSE_GOTOFAV_FIRST))
130 {
131 FIXME("Add support for more than %d Favorites\n", favcount);
132 return;
133 }
134
135 urlbuf = heap_alloc((lstrlenW(url) + 1) * sizeof(WCHAR));
136
137 if(!urlbuf)
138 return;
139
140 lstrcpyW(urlbuf, url);
141
142 item.cbSize = sizeof(item);
143 item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA | MIIM_ID;
144 item.fType = MFT_STRING;
145 item.dwTypeData = title;
146 item.wID = ID_BROWSE_GOTOFAV_FIRST + favcount;
147 item.dwItemData = (ULONG_PTR)urlbuf;
148 InsertMenuItemW(menu, -1, TRUE, &item);
149 }
150
151 static void add_favs_to_menu(HMENU favmenu, HMENU menu, LPCWSTR dir)
152 {
153 WCHAR path[MAX_PATH*2];
154 const WCHAR search[] = {'*',0};
155 WCHAR* filename;
156 HANDLE findhandle;
157 WIN32_FIND_DATAW finddata;
158 IUniformResourceLocatorW* urlobj;
159 IPersistFile* urlfile = NULL;
160 HRESULT res;
161
162 lstrcpyW(path, dir);
163 PathAppendW(path, search);
164
165 findhandle = FindFirstFileW(path, &finddata);
166
167 if(findhandle == INVALID_HANDLE_VALUE)
168 return;
169
170 res = CoCreateInstance(&CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER, &IID_IUniformResourceLocatorW, (PVOID*)&urlobj);
171
172 if(SUCCEEDED(res))
173 res = IUnknown_QueryInterface((IUnknown*)urlobj, &IID_IPersistFile, (PVOID*)&urlfile);
174
175 if(SUCCEEDED(res))
176 {
177 filename = path + lstrlenW(path) - lstrlenW(search);
178
179 do
180 {
181 lstrcpyW(filename, finddata.cFileName);
182
183 if(finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
184 {
185 MENUITEMINFOW item;
186 const WCHAR ignore1[] = {'.','.',0};
187 const WCHAR ignore2[] = {'.',0};
188
189 if(!lstrcmpW(filename, ignore1) || !lstrcmpW(filename, ignore2))
190 continue;
191
192 item.cbSize = sizeof(item);
193 item.fMask = MIIM_STRING | MIIM_SUBMENU;
194 item.dwTypeData = filename;
195 item.hSubMenu = CreatePopupMenu();
196 InsertMenuItemW(menu, -1, TRUE, &item);
197 add_favs_to_menu(favmenu, item.hSubMenu, path);
198 } else
199 {
200 WCHAR* fileext;
201 WCHAR* url = NULL;
202 const WCHAR urlext[] = {'.','u','r','l',0};
203
204 if(lstrcmpiW(PathFindExtensionW(filename), urlext))
205 continue;
206
207 if(FAILED(IPersistFile_Load(urlfile, path, 0)))
208 continue;
209
210 urlobj->lpVtbl->GetURL(urlobj, &url);
211
212 if(!url)
213 continue;
214
215 fileext = filename + lstrlenW(filename) - lstrlenW(urlext);
216 *fileext = 0;
217 add_fav_to_menu(favmenu, menu, filename, url);
218 }
219 } while(FindNextFileW(findhandle, &finddata));
220 }
221
222 if(urlfile)
223 IPersistFile_Release(urlfile);
224
225 if(urlobj)
226 IUnknown_Release((IUnknown*)urlobj);
227
228 FindClose(findhandle);
229 }
230
231 static void add_tbs_to_menu(HMENU menu)
232 {
233 HUSKEY toolbar_handle;
234 WCHAR toolbar_key[] = {'S','o','f','t','w','a','r','e','\\',
235 'M','i','c','r','o','s','o','f','t','\\',
236 'I','n','t','e','r','n','e','t',' ',
237 'E','x','p','l','o','r','e','r','\\',
238 'T','o','o','l','b','a','r',0};
239
240 if(SHRegOpenUSKeyW(toolbar_key, KEY_READ, NULL, &toolbar_handle, TRUE) == ERROR_SUCCESS)
241 {
242 HUSKEY classes_handle;
243 WCHAR classes_key[] = {'S','o','f','t','w','a','r','e','\\',
244 'C','l','a','s','s','e','s','\\','C','L','S','I','D',0};
245 WCHAR guid[39];
246 DWORD value_len = sizeof(guid)/sizeof(guid[0]);
247 int i;
248
249 if(SHRegOpenUSKeyW(classes_key, KEY_READ, NULL, &classes_handle, TRUE) != ERROR_SUCCESS)
250 {
251 SHRegCloseUSKey(toolbar_handle);
252 ERR("Failed to open key %s\n", debugstr_w(classes_key));
253 return;
254 }
255
256 for(i = 0; SHRegEnumUSValueW(toolbar_handle, i, guid, &value_len, NULL, NULL, NULL, SHREGENUM_HKLM) == ERROR_SUCCESS; i++)
257 {
258 WCHAR tb_name[100];
259 DWORD tb_name_len = sizeof(tb_name)/sizeof(tb_name[0]);
260 HUSKEY tb_class_handle;
261 MENUITEMINFOW item;
262 LSTATUS ret;
263 value_len = sizeof(guid)/sizeof(guid[0]);
264
265 if(lstrlenW(guid) != 38)
266 {
267 TRACE("Found invalid IE toolbar entry: %s\n", debugstr_w(guid));
268 continue;
269 }
270
271 if(SHRegOpenUSKeyW(guid, KEY_READ, classes_handle, &tb_class_handle, TRUE) != ERROR_SUCCESS)
272 {
273 ERR("Failed to get class info for %s\n", debugstr_w(guid));
274 continue;
275 }
276
277 ret = SHRegQueryUSValueW(tb_class_handle, NULL, NULL, tb_name, &tb_name_len, TRUE, NULL, 0);
278
279 SHRegCloseUSKey(tb_class_handle);
280
281 if(ret != ERROR_SUCCESS)
282 {
283 ERR("Failed to get toolbar name for %s\n", debugstr_w(guid));
284 continue;
285 }
286
287 item.cbSize = sizeof(item);
288 item.fMask = MIIM_STRING;
289 item.dwTypeData = tb_name;
290 InsertMenuItemW(menu, GetMenuItemCount(menu), TRUE, &item);
291 }
292
293 SHRegCloseUSKey(classes_handle);
294 SHRegCloseUSKey(toolbar_handle);
295 }
296 }
297
298 static HMENU create_ie_menu(void)
299 {
300 HMENU menu = LoadMenuW(ieframe_instance, MAKEINTRESOURCEW(IDR_BROWSE_MAIN_MENU));
301 HMENU favmenu = get_fav_menu(menu);
302 WCHAR path[MAX_PATH];
303
304 add_tbs_to_menu(get_tb_menu(menu));
305
306 if(SHGetFolderPathW(NULL, CSIDL_COMMON_FAVORITES, NULL, SHGFP_TYPE_CURRENT, path) == S_OK)
307 add_favs_to_menu(favmenu, favmenu, path);
308
309 if(SHGetFolderPathW(NULL, CSIDL_FAVORITES, NULL, SHGFP_TYPE_CURRENT, path) == S_OK)
310 add_favs_to_menu(favmenu, favmenu, path);
311
312 return menu;
313 }
314
315 static void ie_navigate(InternetExplorer* This, LPCWSTR url)
316 {
317 VARIANT variant;
318
319 V_VT(&variant) = VT_BSTR;
320 V_BSTR(&variant) = SysAllocString(url);
321
322 IWebBrowser2_Navigate2(&This->IWebBrowser2_iface, &variant, NULL, NULL, NULL, NULL);
323
324 SysFreeString(V_BSTR(&variant));
325 }
326
327 static INT_PTR CALLBACK ie_dialog_open_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
328 {
329 static InternetExplorer* This;
330
331 switch(msg)
332 {
333 case WM_INITDIALOG:
334 This = (InternetExplorer*)lparam;
335 EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
336 return TRUE;
337
338 case WM_COMMAND:
339 switch(LOWORD(wparam))
340 {
341 case IDC_BROWSE_OPEN_URL:
342 {
343 HWND hwndurl = GetDlgItem(hwnd, IDC_BROWSE_OPEN_URL);
344 int len = GetWindowTextLengthW(hwndurl);
345
346 EnableWindow(GetDlgItem(hwnd, IDOK), len != 0);
347 break;
348 }
349 case IDOK:
350 {
351 HWND hwndurl = GetDlgItem(hwnd, IDC_BROWSE_OPEN_URL);
352 int len = GetWindowTextLengthW(hwndurl);
353
354 if(len)
355 {
356 VARIANT url;
357
358 V_VT(&url) = VT_BSTR;
359 V_BSTR(&url) = SysAllocStringLen(NULL, len);
360
361 GetWindowTextW(hwndurl, V_BSTR(&url), len + 1);
362 IWebBrowser2_Navigate2(&This->IWebBrowser2_iface, &url, NULL, NULL, NULL, NULL);
363
364 SysFreeString(V_BSTR(&url));
365 }
366 }
367 /* fall through */
368 case IDCANCEL:
369 EndDialog(hwnd, wparam);
370 return TRUE;
371 }
372 }
373 return FALSE;
374 }
375
376 static void ie_dialog_about(HWND hwnd)
377 {
378 HICON icon = LoadImageW(GetModuleHandleW(0), MAKEINTRESOURCEW(IDI_APPICON), IMAGE_ICON, 48, 48, LR_SHARED);
379
380 ShellAboutW(hwnd, wszWineInternetExplorer, NULL, icon);
381
382 DestroyIcon(icon);
383 }
384
385 #ifdef __REACTOS__
386 static void ie_dialog_properties(HWND hwnd)
387 {
388 ShellExecuteW(hwnd, NULL, L"inetcpl.cpl", NULL, NULL, 0);
389 }
390 #endif
391
392 static void add_tb_separator(InternetExplorer *ie)
393 {
394 TBBUTTON btn;
395
396 ZeroMemory(&btn, sizeof(btn));
397
398 btn.iBitmap = 3;
399 btn.fsStyle = BTNS_SEP;
400 SendMessageW(ie->toolbar_hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&btn);
401 }
402
403 static void add_tb_button(InternetExplorer *ie, int bmp, int cmd, int strId)
404 {
405 TBBUTTON btn;
406 WCHAR buf[30];
407
408 LoadStringW(ieframe_instance, strId, buf, sizeof(buf)/sizeof(buf[0]));
409
410 btn.iBitmap = bmp;
411 btn.idCommand = cmd;
412 btn.fsState = TBSTATE_ENABLED;
413 btn.fsStyle = BTNS_SHOWTEXT;
414 btn.dwData = 0;
415 btn.iString = (INT_PTR)buf;
416
417 SendMessageW(ie->toolbar_hwnd, TB_ADDBUTTONSW, 1, (LPARAM)&btn);
418 }
419
420 static void enable_toolbar_button(InternetExplorer *ie, int command, BOOL enable)
421 {
422 SendMessageW(ie->toolbar_hwnd, TB_ENABLEBUTTON, command, enable);
423 }
424
425 static void create_rebar(InternetExplorer *ie)
426 {
427 HWND hwndRebar;
428 HWND hwndAddress;
429 REBARINFO rebarinf;
430 REBARBANDINFOW bandinf;
431 WCHAR addr[40];
432 HIMAGELIST imagelist;
433 SIZE toolbar_size;
434
435 LoadStringW(ieframe_instance, IDS_ADDRESS, addr, sizeof(addr)/sizeof(addr[0]));
436
437 hwndRebar = CreateWindowExW(WS_EX_TOOLWINDOW, REBARCLASSNAMEW, NULL,
438 WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|RBS_VARHEIGHT|CCS_TOP|CCS_NODIVIDER, 0, 0, 0, 0,
439 ie->frame_hwnd, (HMENU)IDC_BROWSE_REBAR, ieframe_instance, NULL);
440
441 rebarinf.cbSize = sizeof(rebarinf);
442 rebarinf.fMask = 0;
443 rebarinf.himl = NULL;
444
445 SendMessageW(hwndRebar, RB_SETBARINFO, 0, (LPARAM)&rebarinf);
446
447 ie->toolbar_hwnd = CreateWindowExW(TBSTYLE_EX_MIXEDBUTTONS, TOOLBARCLASSNAMEW, NULL, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE | CCS_NORESIZE,
448 0, 0, 0, 0, hwndRebar, (HMENU)IDC_BROWSE_TOOLBAR, ieframe_instance, NULL);
449
450 imagelist = ImageList_LoadImageW(ieframe_instance, MAKEINTRESOURCEW(IDB_IETOOLBAR), 32, 0, CLR_NONE, IMAGE_BITMAP, LR_CREATEDIBSECTION);
451
452 SendMessageW(ie->toolbar_hwnd, TB_SETIMAGELIST, 0, (LPARAM)imagelist);
453 SendMessageW(ie->toolbar_hwnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
454 add_tb_button(ie, 0, ID_BROWSE_BACK, IDS_TB_BACK);
455 add_tb_button(ie, 1, ID_BROWSE_FORWARD, IDS_TB_FORWARD);
456 add_tb_button(ie, 2, ID_BROWSE_STOP, IDS_TB_STOP);
457 add_tb_button(ie, 3, ID_BROWSE_REFRESH, IDS_TB_REFRESH);
458 add_tb_button(ie, 4, ID_BROWSE_HOME, IDS_TB_HOME);
459 add_tb_separator(ie);
460 add_tb_button(ie, 5, ID_BROWSE_PRINT, IDS_TB_PRINT);
461 SendMessageW(ie->toolbar_hwnd, TB_SETBUTTONSIZE, 0, MAKELPARAM(55,50));
462 SendMessageW(ie->toolbar_hwnd, TB_GETMAXSIZE, 0, (LPARAM)&toolbar_size);
463
464 bandinf.cbSize = sizeof(bandinf);
465 bandinf.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE;
466 bandinf.fStyle = RBBS_CHILDEDGE;
467 bandinf.cxMinChild = toolbar_size.cx;
468 bandinf.cyMinChild = toolbar_size.cy+2;
469 bandinf.hwndChild = ie->toolbar_hwnd;
470
471 SendMessageW(hwndRebar, RB_INSERTBANDW, -1, (LPARAM)&bandinf);
472
473 hwndAddress = CreateWindowExW(0, WC_COMBOBOXEXW, NULL, WS_BORDER|WS_CHILD|WS_VISIBLE|CBS_DROPDOWN,
474 0, 0, 100,20,hwndRebar, (HMENU)IDC_BROWSE_ADDRESSBAR, ieframe_instance, NULL);
475
476 bandinf.fMask |= RBBIM_TEXT;
477 bandinf.fStyle = RBBS_CHILDEDGE | RBBS_BREAK;
478 bandinf.lpText = addr;
479 bandinf.cxMinChild = 100;
480 bandinf.cyMinChild = 20;
481 bandinf.hwndChild = hwndAddress;
482
483 SendMessageW(hwndRebar, RB_INSERTBANDW, -1, (LPARAM)&bandinf);
484 }
485
486 static LRESULT iewnd_OnCreate(HWND hwnd, LPCREATESTRUCTW lpcs)
487 {
488 InternetExplorer* This = (InternetExplorer*)lpcs->lpCreateParams;
489 SetWindowLongPtrW(hwnd, 0, (LONG_PTR) lpcs->lpCreateParams);
490
491 This->doc_host.frame_hwnd = This->frame_hwnd = hwnd;
492
493 This->menu = create_ie_menu();
494
495 This->status_hwnd = CreateStatusWindowW(WS_VISIBLE|WS_CHILD|SBT_NOBORDERS|CCS_NODIVIDER,
496 NULL, hwnd, IDC_BROWSE_STATUSBAR);
497 SendMessageW(This->status_hwnd, SB_SIMPLE, TRUE, 0);
498
499 create_rebar(This);
500
501 return 0;
502 }
503
504 static LRESULT iewnd_OnSize(InternetExplorer *This, INT width, INT height)
505 {
506 HWND hwndRebar = GetDlgItem(This->frame_hwnd, IDC_BROWSE_REBAR);
507 INT barHeight = SendMessageW(hwndRebar, RB_GETBARHEIGHT, 0, 0);
508 RECT docarea = {0, 0, width, height};
509
510 SendMessageW(This->status_hwnd, WM_SIZE, 0, 0);
511
512 adjust_ie_docobj_rect(This->frame_hwnd, &docarea);
513
514 if(This->doc_host.hwnd)
515 SetWindowPos(This->doc_host.hwnd, NULL, docarea.left, docarea.top, docarea.right, docarea.bottom,
516 SWP_NOZORDER | SWP_NOACTIVATE);
517
518 SetWindowPos(hwndRebar, NULL, 0, 0, width, barHeight, SWP_NOZORDER | SWP_NOACTIVATE);
519
520 return 0;
521 }
522
523 static LRESULT iewnd_OnNotify(InternetExplorer *This, WPARAM wparam, LPARAM lparam)
524 {
525 NMHDR* hdr = (NMHDR*)lparam;
526
527 if(hdr->idFrom == IDC_BROWSE_ADDRESSBAR && hdr->code == CBEN_ENDEDITW)
528 {
529 NMCBEENDEDITW* info = (NMCBEENDEDITW*)lparam;
530
531 if(info->fChanged && info->iWhy == CBENF_RETURN)
532 {
533 VARIANT vt;
534
535 V_VT(&vt) = VT_BSTR;
536 V_BSTR(&vt) = SysAllocString(info->szText);
537
538 IWebBrowser2_Navigate2(&This->IWebBrowser2_iface, &vt, NULL, NULL, NULL, NULL);
539
540 SysFreeString(V_BSTR(&vt));
541
542 return 0;
543 }
544 }
545
546 if(hdr->idFrom == IDC_BROWSE_REBAR && hdr->code == RBN_HEIGHTCHANGE)
547 {
548 RECT docarea;
549
550 GetClientRect(This->frame_hwnd, &docarea);
551 adjust_ie_docobj_rect(This->frame_hwnd, &docarea);
552
553 if(This->doc_host.hwnd)
554 SetWindowPos(This->doc_host.hwnd, NULL, docarea.left, docarea.top, docarea.right, docarea.bottom,
555 SWP_NOZORDER | SWP_NOACTIVATE);
556 }
557
558 return 0;
559 }
560
561 static LRESULT iewnd_OnDestroy(InternetExplorer *This)
562 {
563 HIMAGELIST list = (HIMAGELIST)SendMessageW(This->toolbar_hwnd, TB_GETIMAGELIST, 0, 0);
564
565 TRACE("%p\n", This);
566
567 free_fav_menu_data(get_fav_menu(This->menu));
568 ImageList_Destroy(list);
569 This->frame_hwnd = NULL;
570
571 return 0;
572 }
573
574 static LRESULT iewnd_OnCommand(InternetExplorer *This, HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
575 {
576 switch(LOWORD(wparam))
577 {
578 case ID_BROWSE_OPEN:
579 DialogBoxParamW(ieframe_instance, MAKEINTRESOURCEW(IDD_BROWSE_OPEN), hwnd, ie_dialog_open_proc, (LPARAM)This);
580 break;
581
582 case ID_BROWSE_PRINT:
583 if(This->doc_host.document)
584 {
585 IOleCommandTarget* target;
586
587 if(FAILED(IUnknown_QueryInterface(This->doc_host.document, &IID_IOleCommandTarget, (LPVOID*)&target)))
588 break;
589
590 IOleCommandTarget_Exec(target, &CGID_MSHTML, IDM_PRINT, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
591
592 IOleCommandTarget_Release(target);
593 }
594 break;
595
596 case ID_BROWSE_HOME:
597 IWebBrowser2_GoHome(&This->IWebBrowser2_iface);
598 break;
599
600 case ID_BROWSE_BACK:
601 IWebBrowser2_GoBack(&This->IWebBrowser2_iface);
602 break;
603
604 case ID_BROWSE_FORWARD:
605 IWebBrowser2_GoForward(&This->IWebBrowser2_iface);
606 break;
607
608 case ID_BROWSE_STOP:
609 IWebBrowser2_Stop(&This->IWebBrowser2_iface);
610 break;
611
612 case ID_BROWSE_REFRESH:
613 IWebBrowser2_Refresh(&This->IWebBrowser2_iface);
614 break;
615
616 case ID_BROWSE_ABOUT:
617 ie_dialog_about(hwnd);
618 break;
619
620 #ifdef __REACTOS__
621 case ID_BROWSE_PROPERTIES:
622 ie_dialog_properties(hwnd);
623 break;
624 #endif
625
626 case ID_BROWSE_QUIT:
627 ShowWindow(hwnd, SW_HIDE);
628 break;
629
630 default:
631 if(LOWORD(wparam) >= ID_BROWSE_GOTOFAV_FIRST && LOWORD(wparam) <= ID_BROWSE_GOTOFAV_MAX)
632 {
633 LPCWSTR url = get_fav_url_from_id(get_fav_menu(This->menu), LOWORD(wparam));
634
635 if(url)
636 ie_navigate(This, url);
637 }
638 return DefWindowProcW(hwnd, msg, wparam, lparam);
639 }
640 return 0;
641 }
642
643 static LRESULT update_addrbar(InternetExplorer *This, LPARAM lparam)
644 {
645 HWND hwndRebar = GetDlgItem(This->frame_hwnd, IDC_BROWSE_REBAR);
646 HWND hwndAddress = GetDlgItem(hwndRebar, IDC_BROWSE_ADDRESSBAR);
647 HWND hwndEdit = (HWND)SendMessageW(hwndAddress, CBEM_GETEDITCONTROL, 0, 0);
648 LPCWSTR url = (LPCWSTR)lparam;
649
650 SendMessageW(hwndEdit, WM_SETTEXT, 0, (LPARAM)url);
651
652 return 0;
653 }
654
655 static LRESULT WINAPI ie_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
656 {
657 InternetExplorer *This = (InternetExplorer*) GetWindowLongPtrW(hwnd, 0);
658
659 switch (msg)
660 {
661 case WM_CREATE:
662 return iewnd_OnCreate(hwnd, (LPCREATESTRUCTW)lparam);
663 case WM_CLOSE:
664 TRACE("WM_CLOSE\n");
665 ShowWindow(hwnd, SW_HIDE);
666 return 0;
667 case WM_SHOWWINDOW:
668 TRACE("WM_SHOWWINDOW %lx\n", wparam);
669 if(wparam) {
670 IWebBrowser2_AddRef(&This->IWebBrowser2_iface);
671 InterlockedIncrement(&This->extern_ref);
672 }else {
673 release_extern_ref(This, TRUE);
674 IWebBrowser2_Release(&This->IWebBrowser2_iface);
675 }
676 break;
677 case WM_DESTROY:
678 return iewnd_OnDestroy(This);
679 case WM_SIZE:
680 return iewnd_OnSize(This, LOWORD(lparam), HIWORD(lparam));
681 case WM_COMMAND:
682 return iewnd_OnCommand(This, hwnd, msg, wparam, lparam);
683 case WM_NOTIFY:
684 return iewnd_OnNotify(This, wparam, lparam);
685 case WM_DOCHOSTTASK:
686 return process_dochost_tasks(&This->doc_host);
687 case WM_UPDATEADDRBAR:
688 return update_addrbar(This, lparam);
689 }
690 return DefWindowProcW(hwnd, msg, wparam, lparam);
691 }
692
693 void register_iewindow_class(void)
694 {
695 WNDCLASSEXW wc;
696
697 memset(&wc, 0, sizeof wc);
698 wc.cbSize = sizeof(wc);
699 wc.style = 0;
700 wc.lpfnWndProc = ie_window_proc;
701 wc.cbClsExtra = 0;
702 wc.cbWndExtra = sizeof(InternetExplorer*);
703 wc.hInstance = ieframe_instance;
704 wc.hIcon = LoadIconW(GetModuleHandleW(0), MAKEINTRESOURCEW(IDI_APPICON));
705 wc.hIconSm = LoadImageW(GetModuleHandleW(0), MAKEINTRESOURCEW(IDI_APPICON), IMAGE_ICON,
706 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED);
707 wc.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
708 wc.hbrBackground = 0;
709 wc.lpszClassName = szIEWinFrame;
710 wc.lpszMenuName = NULL;
711
712 RegisterClassExW(&wc);
713 }
714
715 void unregister_iewindow_class(void)
716 {
717 UnregisterClassW(szIEWinFrame, ieframe_instance);
718 }
719
720 static void create_frame_hwnd(InternetExplorer *This)
721 {
722 CreateWindowExW(
723 WS_EX_WINDOWEDGE,
724 szIEWinFrame, wszWineInternetExplorer,
725 WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
726 | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
727 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
728 NULL, NULL /* FIXME */, ieframe_instance, This);
729
730 create_doc_view_hwnd(&This->doc_host);
731 }
732
733 static inline InternetExplorer *impl_from_DocHost(DocHost *iface)
734 {
735 return CONTAINING_RECORD(iface, InternetExplorer, doc_host);
736 }
737
738 static ULONG IEDocHost_addref(DocHost *iface)
739 {
740 InternetExplorer *This = impl_from_DocHost(iface);
741 return IWebBrowser2_AddRef(&This->IWebBrowser2_iface);
742 }
743
744 static ULONG IEDocHost_release(DocHost *iface)
745 {
746 InternetExplorer *This = impl_from_DocHost(iface);
747 return IWebBrowser2_Release(&This->IWebBrowser2_iface);
748 }
749
750 static void DocHostContainer_get_docobj_rect(DocHost *This, RECT *rc)
751 {
752 GetClientRect(This->frame_hwnd, rc);
753 adjust_ie_docobj_rect(This->frame_hwnd, rc);
754 }
755
756 static HRESULT DocHostContainer_set_status_text(DocHost *iface, const WCHAR *text)
757 {
758 InternetExplorer *This = impl_from_DocHost(iface);
759 return update_ie_statustext(This, text);
760 }
761
762 static void DocHostContainer_on_command_state_change(DocHost *iface, LONG command, BOOL enable)
763 {
764 InternetExplorer *This = impl_from_DocHost(iface);
765
766 switch(command) {
767 case CSC_NAVIGATEBACK:
768 enable_toolbar_button(This, ID_BROWSE_BACK, enable);
769 break;
770 case CSC_NAVIGATEFORWARD:
771 enable_toolbar_button(This, ID_BROWSE_FORWARD, enable);
772 break;
773 }
774 }
775
776 static void DocHostContainer_set_url(DocHost* iface, const WCHAR *url)
777 {
778 InternetExplorer *This = impl_from_DocHost(iface);
779
780 This->nohome = FALSE;
781 SendMessageW(This->frame_hwnd, WM_UPDATEADDRBAR, 0, (LPARAM)url);
782 }
783
784 static const IDocHostContainerVtbl DocHostContainerVtbl = {
785 IEDocHost_addref,
786 IEDocHost_release,
787 DocHostContainer_get_docobj_rect,
788 DocHostContainer_set_status_text,
789 DocHostContainer_on_command_state_change,
790 DocHostContainer_set_url
791 };
792
793 static HRESULT create_ie(InternetExplorer **ret_obj)
794 {
795 InternetExplorer *ret;
796
797 ret = heap_alloc_zero(sizeof(InternetExplorer));
798 if(!ret)
799 return E_OUTOFMEMORY;
800
801 ret->ref = 1;
802
803 DocHost_Init(&ret->doc_host, &ret->IWebBrowser2_iface, &DocHostContainerVtbl);
804
805 InternetExplorer_WebBrowser_Init(ret);
806
807 HlinkFrame_Init(&ret->hlink_frame, (IUnknown*)&ret->IWebBrowser2_iface, &ret->doc_host);
808
809 create_frame_hwnd(ret);
810
811 InterlockedIncrement(&obj_cnt);
812 list_add_tail(&ie_list, &ret->entry);
813 *ret_obj = ret;
814 return S_OK;
815 }
816
817 HRESULT WINAPI InternetExplorer_Create(IClassFactory *iface, IUnknown *pOuter, REFIID riid, void **ppv)
818 {
819 InternetExplorer *ret;
820 HRESULT hres;
821
822 TRACE("(%p %s %p)\n", pOuter, debugstr_guid(riid), ppv);
823
824 hres = create_ie(&ret);
825 if(FAILED(hres))
826 return hres;
827
828 hres = IWebBrowser2_QueryInterface(&ret->IWebBrowser2_iface, riid, ppv);
829 IWebBrowser2_Release(&ret->IWebBrowser2_iface);
830 if(FAILED(hres))
831 return hres;
832
833 return S_OK;
834 }
835
836 void released_obj(void)
837 {
838 if(!InterlockedDecrement(&obj_cnt))
839 PostQuitMessage(0);
840 }
841
842 static BOOL create_ie_window(const WCHAR *cmdline)
843 {
844 InternetExplorer *ie;
845 HRESULT hres;
846
847 hres = create_ie(&ie);
848 if(FAILED(hres))
849 return FALSE;
850
851 IWebBrowser2_put_Visible(&ie->IWebBrowser2_iface, VARIANT_TRUE);
852 IWebBrowser2_put_MenuBar(&ie->IWebBrowser2_iface, VARIANT_TRUE);
853
854 if(!*cmdline) {
855 IWebBrowser2_GoHome(&ie->IWebBrowser2_iface);
856 }else {
857 VARIANT var_url;
858 int cmdlen;
859
860 static const WCHAR nohomeW[] = {'-','n','o','h','o','m','e'};
861
862 while(*cmdline == ' ' || *cmdline == '\t')
863 cmdline++;
864 cmdlen = strlenW(cmdline);
865 if(cmdlen > 2 && cmdline[0] == '"' && cmdline[cmdlen-1] == '"') {
866 cmdline++;
867 cmdlen -= 2;
868 }
869
870 if(cmdlen == sizeof(nohomeW)/sizeof(*nohomeW) && !memcmp(cmdline, nohomeW, sizeof(nohomeW))) {
871 ie->nohome = TRUE;
872 }else {
873 V_VT(&var_url) = VT_BSTR;
874
875 V_BSTR(&var_url) = SysAllocStringLen(cmdline, cmdlen);
876
877 /* navigate to the first page */
878 IWebBrowser2_Navigate2(&ie->IWebBrowser2_iface, &var_url, NULL, NULL, NULL, NULL);
879
880 SysFreeString(V_BSTR(&var_url));
881 }
882 }
883
884 IWebBrowser2_Release(&ie->IWebBrowser2_iface);
885 return TRUE;
886 }
887
888 static HDDEDATA open_dde_url(WCHAR *dde_url)
889 {
890 InternetExplorer *ie = NULL, *iter;
891 WCHAR *url, *url_end;
892 VARIANT urlv;
893 HRESULT hres;
894
895 TRACE("%s\n", debugstr_w(dde_url));
896
897 url = dde_url;
898 if(*url == '"') {
899 url++;
900 url_end = strchrW(url, '"');
901 if(!url_end) {
902 FIXME("missing string terminator\n");
903 return 0;
904 }
905 *url_end = 0;
906 }else {
907 url_end = strchrW(url, ',');
908 if(url_end)
909 *url_end = 0;
910 else
911 url_end = url + strlenW(url);
912 }
913
914 LIST_FOR_EACH_ENTRY(iter, &ie_list, InternetExplorer, entry) {
915 if(iter->nohome) {
916 IWebBrowser2_AddRef(&iter->IWebBrowser2_iface);
917 ie = iter;
918 break;
919 }
920 }
921
922 if(!ie) {
923 hres = create_ie(&ie);
924 if(FAILED(hres))
925 return 0;
926 }
927
928 IWebBrowser2_put_Visible(&ie->IWebBrowser2_iface, VARIANT_TRUE);
929 IWebBrowser2_put_MenuBar(&ie->IWebBrowser2_iface, VARIANT_TRUE);
930
931 V_VT(&urlv) = VT_BSTR;
932 V_BSTR(&urlv) = SysAllocStringLen(url, url_end-url);
933 if(!V_BSTR(&urlv)) {
934 IWebBrowser2_Release(&ie->IWebBrowser2_iface);
935 return 0;
936 }
937
938 hres = IWebBrowser2_Navigate2(&ie->IWebBrowser2_iface, &urlv, NULL, NULL, NULL, NULL);
939 if(FAILED(hres))
940 return 0;
941
942 IWebBrowser2_Release(&ie->IWebBrowser2_iface);
943 return ULongToHandle(DDE_FACK);
944 }
945
946 static HDDEDATA WINAPI dde_proc(UINT type, UINT uFmt, HCONV hConv, HSZ hsz1, HSZ hsz2, HDDEDATA data,
947 ULONG_PTR dwData1, ULONG_PTR dwData2)
948 {
949 switch(type) {
950 case XTYP_CONNECT:
951 TRACE("XTYP_CONNECT %p\n", hsz1);
952 return ULongToHandle(!DdeCmpStringHandles(hsz1, ddestr_openurl));
953
954 case XTYP_EXECUTE: {
955 WCHAR *url;
956 DWORD size;
957 HDDEDATA ret;
958
959 TRACE("XTYP_EXECUTE %p\n", data);
960
961 size = DdeGetData(data, NULL, 0, 0);
962 if(!size) {
963 WARN("size = 0\n");
964 break;
965 }
966
967 url = heap_alloc(size);
968 if(!url)
969 break;
970
971 if(DdeGetData(data, (BYTE*)url, size, 0) != size) {
972 ERR("error during read\n");
973 heap_free(url);
974 break;
975 }
976
977 ret = open_dde_url(url);
978
979 heap_free(url);
980 return ret;
981 }
982
983 case XTYP_REQUEST:
984 FIXME("XTYP_REQUEST\n");
985 break;
986
987 default:
988 TRACE("type %d\n", type);
989 }
990
991 return NULL;
992 }
993
994 static void init_dde(void)
995 {
996 UINT res;
997
998 static const WCHAR iexploreW[] = {'I','E','x','p','l','o','r','e',0};
999 static const WCHAR openurlW[] = {'W','W','W','_','O','p','e','n','U','R','L',0};
1000
1001 res = DdeInitializeW(&dde_inst, dde_proc, CBF_SKIP_ALLNOTIFICATIONS | CBF_FAIL_ADVISES | CBF_FAIL_POKES, 0);
1002 if(res != DMLERR_NO_ERROR) {
1003 WARN("DdeInitialize failed: %u\n", res);
1004 return;
1005 }
1006
1007 ddestr_iexplore = DdeCreateStringHandleW(dde_inst, iexploreW, CP_WINUNICODE);
1008 if(!ddestr_iexplore)
1009 WARN("Failed to create string handle: %u\n", DdeGetLastError(dde_inst));
1010
1011 ddestr_openurl = DdeCreateStringHandleW(dde_inst, openurlW, CP_WINUNICODE);
1012 if(!ddestr_openurl)
1013 WARN("Failed to create string handle: %u\n", DdeGetLastError(dde_inst));
1014
1015 if(!DdeNameService(dde_inst, ddestr_iexplore, 0, DNS_REGISTER))
1016 WARN("DdeNameService failed\n");
1017 }
1018
1019 static void release_dde(void)
1020 {
1021 if(ddestr_iexplore)
1022 DdeNameService(dde_inst, ddestr_iexplore, 0, DNS_UNREGISTER);
1023 if(ddestr_openurl)
1024 DdeFreeStringHandle(dde_inst, ddestr_openurl);
1025 if(ddestr_iexplore)
1026 DdeFreeStringHandle(dde_inst, ddestr_iexplore);
1027 DdeUninitialize(dde_inst);
1028 }
1029
1030 /******************************************************************
1031 * IEWinMain (ieframe.101)
1032 *
1033 * Only returns on error.
1034 */
1035 DWORD WINAPI IEWinMain(const WCHAR *cmdline, int nShowWindow)
1036 {
1037 MSG msg;
1038 HRESULT hres;
1039
1040 static const WCHAR embeddingW[] = {'-','e','m','b','e','d','d','i','n','g',0};
1041
1042 TRACE("%s %d\n", debugstr_w(cmdline), nShowWindow);
1043
1044 CoInitialize(NULL);
1045
1046 hres = register_class_object(TRUE);
1047 if(FAILED(hres)) {
1048 CoUninitialize();
1049 ExitProcess(1);
1050 }
1051
1052 init_dde();
1053
1054 if(strcmpiW(cmdline, embeddingW)) {
1055 if(!create_ie_window(cmdline)) {
1056 CoUninitialize();
1057 ExitProcess(1);
1058 }
1059 }
1060
1061 /* run the message loop for this thread */
1062 while (GetMessageW(&msg, 0, 0, 0))
1063 {
1064 TranslateMessage(&msg);
1065 DispatchMessageW(&msg);
1066 }
1067
1068 register_class_object(FALSE);
1069 release_dde();
1070
1071 CoUninitialize();
1072
1073 ExitProcess(0);
1074 return 0;
1075 }