Made WinLauncher have better error handling, crash reporting, and modifiability.
[WebKit-https.git] / Tools / WinLauncher / WinLauncher.cpp
1 /*
2  * Copyright (C) 2006, 2008, 2013 Apple Computer, Inc.  All rights reserved.
3  * Copyright (C) 2009, 2011 Brent Fulgham.  All rights reserved.
4  * Copyright (C) 2009, 2010, 2011 Appcelerator, Inc. All rights reserved.
5  * Copyright (C) 2013 Alex Christensen. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
27  */
28
29 #include "stdafx.h"
30 #include "WinLauncher.h"
31
32 #include "AccessibilityDelegate.h"
33 #include "DOMDefaultImpl.h"
34 #include "PrintWebUIDelegate.h"
35 #include "WinLauncherLibResource.h"
36 #include "WinLauncherReplace.h"
37 #include <WebKit/WebKitCOMAPI.h>
38 #include <wtf/ExportMacros.h>
39 #include <wtf/Platform.h>
40
41 #if USE(CF)
42 #include <CoreFoundation/CFRunLoop.h>
43 #endif
44
45 #include <algorithm>
46 #include <assert.h>
47 #include <comip.h>
48 #include <commctrl.h>
49 #include <commdlg.h>
50 #include <comutil.h>
51 #include <dbghelp.h>
52 #include <functional>
53 #include <objbase.h>
54 #include <shellapi.h>
55 #include <shlobj.h>
56 #include <shlwapi.h>
57 #include <string>
58 #include <vector>
59 #include <wininet.h>
60
61 #define MAX_LOADSTRING 100
62 #define URLBAR_HEIGHT  24
63 #define CONTROLBUTTON_WIDTH 24
64
65 static const int maxHistorySize = 10;
66
67 typedef _com_ptr_t<_com_IIID<IWebFrame, &__uuidof(IWebFrame)>> IWebFramePtr;
68 typedef _com_ptr_t<_com_IIID<IWebHistory, &__uuidof(IWebHistory)>> IWebHistoryPtr;
69 typedef _com_ptr_t<_com_IIID<IWebHistoryItem, &__uuidof(IWebHistoryItem)>> IWebHistoryItemPtr;
70 typedef _com_ptr_t<_com_IIID<IWebInspector, &__uuidof(IWebInspector)>> IWebInspectorPtr;
71 typedef _com_ptr_t<_com_IIID<IWebMutableURLRequest, &__uuidof(IWebMutableURLRequest)>> IWebMutableURLRequestPtr;
72 typedef _com_ptr_t<_com_IIID<IWebPreferences, &__uuidof(IWebPreferences)>> IWebPreferencesPtr;
73 typedef _com_ptr_t<_com_IIID<IWebPreferencesPrivate, &__uuidof(IWebPreferencesPrivate)>> IWebPreferencesPrivatePtr;
74 typedef _com_ptr_t<_com_IIID<IWebView, &__uuidof(IWebView)>> IWebViewPtr;
75 typedef _com_ptr_t<_com_IIID<IWebViewPrivate, &__uuidof(IWebViewPrivate)>> IWebViewPrivatePtr;
76
77 // Global Variables:
78 HINSTANCE hInst;                                // current instance
79 HWND hMainWnd;
80 HWND hURLBarWnd;
81 HWND hBackButtonWnd;
82 HWND hForwardButtonWnd;
83 WNDPROC DefEditProc = 0;
84 WNDPROC DefButtonProc = 0;
85 WNDPROC DefWebKitProc = 0;
86 IWebInspectorPtr gInspector;
87 IWebViewPtr gWebView;
88 IWebViewPrivatePtr gWebViewPrivate;
89 IWebPreferencesPtr gStandardPreferences;
90 IWebPreferencesPrivatePtr gPrefsPrivate;
91 HWND gViewWindow = 0;
92 WinLauncherWebHost* gWebHost = 0;
93 PrintWebUIDelegate* gPrintDelegate = 0;
94 AccessibilityDelegate* gAccessibilityDelegate = 0;
95 IWebHistoryPtr gWebHistory;
96 std::vector<IWebHistoryItemPtr> gHistoryItems;
97 TCHAR szTitle[MAX_LOADSTRING];                    // The title bar text
98 TCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name
99
100 // Support moving the transparent window
101 POINT s_windowPosition = { 100, 100 };
102 SIZE s_windowSize = { 800, 400 };
103 bool s_usesLayeredWebView = false;
104 bool s_fullDesktop = false;
105
106 // Forward declarations of functions included in this code module:
107 ATOM                MyRegisterClass(HINSTANCE hInstance);
108 LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
109 INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
110 LRESULT CALLBACK    EditProc(HWND, UINT, WPARAM, LPARAM);
111 LRESULT CALLBACK    BackButtonProc(HWND, UINT, WPARAM, LPARAM);
112 LRESULT CALLBACK    ForwardButtonProc(HWND, UINT, WPARAM, LPARAM);
113 LRESULT CALLBACK    ReloadButtonProc(HWND, UINT, WPARAM, LPARAM);
114
115 static void loadURL(BSTR urlBStr);
116
117 static bool usesLayeredWebView()
118 {
119     return s_usesLayeredWebView;
120 }
121
122 static bool shouldUseFullDesktop()
123 {
124     return s_fullDesktop;
125 }
126
127 class SimpleEventListener : public DOMEventListener {
128 public:
129     SimpleEventListener(LPWSTR type)
130     {
131         wcsncpy_s(m_eventType, 100, type, 100);
132         m_eventType[99] = 0;
133     }
134
135     virtual HRESULT STDMETHODCALLTYPE handleEvent(IDOMEvent* evt)
136     {
137         wchar_t message[255];
138         wcscpy_s(message, 255, m_eventType);
139         wcscat_s(message, 255, L" event fired!");
140         ::MessageBox(0, message, L"Event Handler", MB_OK);
141         return S_OK;
142     }
143
144 private:
145     wchar_t m_eventType[100];
146 };
147
148 typedef _com_ptr_t<_com_IIID<IWebDataSource, &__uuidof(IWebDataSource)>> IWebDataSourcePtr;
149
150 HRESULT WinLauncherWebHost::updateAddressBar(IWebView* webView)
151 {
152     IWebFramePtr mainFrame;
153     HRESULT hr = webView->mainFrame(&mainFrame.GetInterfacePtr());
154     if (FAILED(hr))
155         return 0;
156
157     IWebDataSourcePtr dataSource;
158     hr = mainFrame->dataSource(&dataSource.GetInterfacePtr());
159     if (FAILED(hr) || !dataSource)
160         hr = mainFrame->provisionalDataSource(&dataSource.GetInterfacePtr());
161     if (FAILED(hr) || !dataSource)
162         return 0;
163
164     IWebMutableURLRequestPtr request;
165     hr = dataSource->request(&request.GetInterfacePtr());
166     if (FAILED(hr) || !request)
167         return 0;
168
169     _bstr_t frameURL;
170     hr = request->mainDocumentURL(frameURL.GetAddress());
171     if (FAILED(hr))
172         return 0;
173
174     ::SendMessage(hURLBarWnd, static_cast<UINT>(WM_SETTEXT), 0, reinterpret_cast<LPARAM>(frameURL.GetBSTR()));
175
176     return 0;
177 }
178
179 HRESULT WinLauncherWebHost::didFailProvisionalLoadWithError(IWebView*, IWebError *error, IWebFrame*)
180 {
181     _bstr_t errorDescription;
182     HRESULT hr = error->localizedDescription(errorDescription.GetAddress());
183     if (FAILED(hr))
184         errorDescription = L"Failed to load page and to localize error description.";
185
186     if (_wcsicmp(errorDescription, L"Cancelled"))
187         ::MessageBoxW(0, static_cast<LPCWSTR>(errorDescription), L"Error", MB_APPLMODAL | MB_OK);
188
189     return S_OK;
190 }
191
192 HRESULT STDMETHODCALLTYPE WinLauncherWebHost::QueryInterface(REFIID riid, void** ppvObject)
193 {
194     *ppvObject = 0;
195     if (IsEqualGUID(riid, IID_IUnknown))
196         *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
197     else if (IsEqualGUID(riid, IID_IWebFrameLoadDelegate))
198         *ppvObject = static_cast<IWebFrameLoadDelegate*>(this);
199     else
200         return E_NOINTERFACE;
201
202     AddRef();
203     return S_OK;
204 }
205
206 ULONG STDMETHODCALLTYPE WinLauncherWebHost::AddRef(void)
207 {
208     return ++m_refCount;
209 }
210
211 ULONG STDMETHODCALLTYPE WinLauncherWebHost::Release(void)
212 {
213     ULONG newRef = --m_refCount;
214     if (!newRef)
215         delete(this);
216
217     return newRef;
218 }
219
220 static void updateMenuItemForHistoryItem(HMENU menu, IWebHistoryItem& historyItem, int currentHistoryItem)
221 {
222     UINT menuID = IDM_HISTORY_LINK0 + currentHistoryItem;
223
224     MENUITEMINFO menuItemInfo = {0};
225     menuItemInfo.cbSize = sizeof(MENUITEMINFO);
226     menuItemInfo.fMask = MIIM_TYPE;
227     menuItemInfo.fType = MFT_STRING;
228
229     _bstr_t title;
230     historyItem.title(title.GetAddress());
231     menuItemInfo.dwTypeData = static_cast<LPWSTR>(title);
232
233     ::SetMenuItemInfo(menu, menuID, FALSE, &menuItemInfo);
234     ::EnableMenuItem(menu, menuID, MF_BYCOMMAND | MF_ENABLED);
235 }
236
237 static void showLastVisitedSites(IWebView& webView)
238 {
239     HMENU menu = ::GetMenu(hMainWnd);
240
241     _com_ptr_t<_com_IIID<IWebBackForwardList, &__uuidof(IWebBackForwardList)>> backForwardList;
242     HRESULT hr = webView.backForwardList(&backForwardList.GetInterfacePtr());
243     if (FAILED(hr))
244         return;
245
246     int capacity = 0;
247     hr = backForwardList->capacity(&capacity);
248     if (FAILED(hr))
249         return;
250
251     int backCount = 0;
252     hr = backForwardList->backListCount(&backCount);
253     if (FAILED(hr))
254         return;
255
256     UINT backSetting = MF_BYCOMMAND | (backCount) ? MF_ENABLED : MF_DISABLED;
257     ::EnableMenuItem(menu, IDM_HISTORY_BACKWARD, backSetting);
258
259     int forwardCount = 0;
260     hr = backForwardList->forwardListCount(&forwardCount);
261     if (FAILED(hr))
262         return;
263
264     UINT forwardSetting = MF_BYCOMMAND | (forwardCount) ? MF_ENABLED : MF_DISABLED;
265     ::EnableMenuItem(menu, IDM_HISTORY_FORWARD, forwardSetting);
266
267     IWebHistoryItemPtr currentItem;
268     hr = backForwardList->currentItem(&currentItem.GetInterfacePtr());
269     if (FAILED(hr))
270         return;
271
272     hr = gWebHistory->addItems(1, &currentItem.GetInterfacePtr());
273     if (FAILED(hr))
274         return;
275
276     _com_ptr_t<_com_IIID<IWebHistoryPrivate, &__uuidof(IWebHistoryPrivate)>> webHistory;
277     hr = gWebHistory->QueryInterface(IID_IWebHistoryPrivate, reinterpret_cast<void**>(&webHistory.GetInterfacePtr()));
278     if (FAILED(hr))
279         return;
280
281     int totalListCount = 0;
282     hr = webHistory->allItems(&totalListCount, 0);
283     if (FAILED(hr))
284         return;
285
286     gHistoryItems.resize(totalListCount);
287
288     std::vector<IWebHistoryItem*> historyToLoad(totalListCount);
289     hr = webHistory->allItems(&totalListCount, historyToLoad.data());
290     if (FAILED(hr))
291         return;
292
293     size_t i = 0;
294     for (auto cur = historyToLoad.begin(); cur != historyToLoad.end(); ++cur) {
295         gHistoryItems[i].Attach(*cur);
296         ++i;
297     }
298
299     int allItemsOffset = 0;
300     if (totalListCount > maxHistorySize)
301         allItemsOffset = totalListCount - maxHistorySize;
302
303     int currentHistoryItem = 0;
304     for (int i = 0; i < totalListCount; ++i) {
305         updateMenuItemForHistoryItem(menu, *(gHistoryItems[allItemsOffset + currentHistoryItem]), currentHistoryItem);
306         ++currentHistoryItem;
307     }
308
309     // Hide any history we aren't using yet.
310     for (int i = currentHistoryItem; i < maxHistorySize; ++i)
311         ::EnableMenuItem(menu, IDM_HISTORY_LINK0 + i, MF_BYCOMMAND | MF_DISABLED);
312 }
313
314 typedef _com_ptr_t<_com_IIID<IDOMDocument, &__uuidof(IDOMDocument)>> IDOMDocumentPtr;
315 typedef _com_ptr_t<_com_IIID<IDOMElement, &__uuidof(IDOMElement)>> IDOMElementPtr;
316 typedef _com_ptr_t<_com_IIID<IDOMEventTarget, &__uuidof(IDOMEventTarget)>> IDOMEventTargetPtr;
317
318 HRESULT WinLauncherWebHost::didFinishLoadForFrame(IWebView* webView, IWebFrame* frame)
319 {
320     IDOMDocumentPtr doc;
321     frame->DOMDocument(&doc.GetInterfacePtr());
322
323     IDOMElementPtr element;
324     IDOMEventTargetPtr target;
325
326     showLastVisitedSites(*webView);
327
328     // The following is for the test page:
329     HRESULT hr = doc->getElementById(L"webkit logo", &element.GetInterfacePtr());
330     if (!SUCCEEDED(hr))
331         return hr;
332
333     hr = element->QueryInterface(IID_IDOMEventTarget, reinterpret_cast<void**>(&target.GetInterfacePtr()));
334     if (!SUCCEEDED(hr))
335         return hr;
336
337     hr = target->addEventListener(L"click", new SimpleEventListener (L"webkit logo click"), FALSE);
338     if (!SUCCEEDED(hr))
339         return hr;
340
341     return hr;
342 }
343
344 static void resizeSubViews()
345 {
346     if (usesLayeredWebView() || !gViewWindow)
347         return;
348
349     RECT rcClient;
350     GetClientRect(hMainWnd, &rcClient);
351     MoveWindow(hBackButtonWnd, 0, 0, CONTROLBUTTON_WIDTH, URLBAR_HEIGHT, TRUE);
352     MoveWindow(hForwardButtonWnd, CONTROLBUTTON_WIDTH, 0, CONTROLBUTTON_WIDTH, URLBAR_HEIGHT, TRUE);
353     MoveWindow(hURLBarWnd, CONTROLBUTTON_WIDTH * 2, 0, rcClient.right, URLBAR_HEIGHT, TRUE);
354     MoveWindow(gViewWindow, 0, URLBAR_HEIGHT, rcClient.right, rcClient.bottom - URLBAR_HEIGHT, TRUE);
355 }
356
357 static void subclassForLayeredWindow()
358 {
359     hMainWnd = gViewWindow;
360 #if defined _M_AMD64 || defined _WIN64
361     DefWebKitProc = reinterpret_cast<WNDPROC>(::GetWindowLongPtr(hMainWnd, GWLP_WNDPROC));
362     ::SetWindowLongPtr(hMainWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WndProc));
363 #else
364     DefWebKitProc = reinterpret_cast<WNDPROC>(::GetWindowLong(hMainWnd, GWL_WNDPROC));
365     ::SetWindowLong(hMainWnd, GWL_WNDPROC, reinterpret_cast<LONG_PTR>(WndProc));
366 #endif
367 }
368
369 static void computeFullDesktopFrame()
370 {
371     RECT desktop;
372     if (!::SystemParametersInfo(SPI_GETWORKAREA, 0, static_cast<void*>(&desktop), 0))
373         return;
374
375     s_windowPosition.x = 0;
376     s_windowPosition.y = 0;
377     s_windowSize.cx = desktop.right - desktop.left;
378     s_windowSize.cy = desktop.bottom - desktop.top;
379 }
380
381 BOOL WINAPI DllMain(HINSTANCE dllInstance, DWORD reason, LPVOID)
382 {
383     if (reason == DLL_PROCESS_ATTACH)
384         hInst = dllInstance;
385
386     return TRUE;
387 }
388
389 static bool setToDefaultPreferences()
390 {
391     HRESULT hr = gStandardPreferences->QueryInterface(IID_IWebPreferencesPrivate, reinterpret_cast<void**>(&gPrefsPrivate.GetInterfacePtr()));
392     if (!SUCCEEDED(hr))
393         return false;
394
395 #if USE(CG)
396     gStandardPreferences->setAVFoundationEnabled(TRUE);
397     gPrefsPrivate->setAcceleratedCompositingEnabled(TRUE);
398 #endif
399
400     gPrefsPrivate->setFullScreenEnabled(TRUE);
401     gPrefsPrivate->setShowDebugBorders(FALSE);
402     gPrefsPrivate->setShowRepaintCounter(FALSE);
403
404     gStandardPreferences->setLoadsImagesAutomatically(TRUE);
405     gPrefsPrivate->setAuthorAndUserStylesEnabled(TRUE);
406     gStandardPreferences->setJavaScriptEnabled(TRUE);
407     gPrefsPrivate->setAllowUniversalAccessFromFileURLs(FALSE);
408     gPrefsPrivate->setAllowFileAccessFromFileURLs(TRUE);
409
410     gPrefsPrivate->setDeveloperExtrasEnabled(TRUE);
411
412     return true;
413 }
414
415 void createCrashReport(EXCEPTION_POINTERS* exceptionPointers)
416 {
417     wchar_t appDataDirectory[MAX_PATH];
418     if (FAILED(SHGetFolderPathW(0, CSIDL_LOCAL_APPDATA | CSIDL_FLAG_CREATE, 0, 0, appDataDirectory)))
419         return;
420
421     std::wstring directory = std::wstring(appDataDirectory) + L"\\WinLauncher";
422     if (::SHCreateDirectoryEx(0, directory.c_str(), 0) != ERROR_SUCCESS
423         && ::GetLastError() != ERROR_FILE_EXISTS
424         && ::GetLastError() != ERROR_ALREADY_EXISTS)
425         return;
426
427     std::wstring fileName = directory + L"\\CrashReport.dmp";
428     HANDLE miniDumpFile = ::CreateFile(fileName.c_str(), GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
429
430     if (miniDumpFile && miniDumpFile != INVALID_HANDLE_VALUE) {
431
432         MINIDUMP_EXCEPTION_INFORMATION mdei;
433         mdei.ThreadId = ::GetCurrentThreadId();
434         mdei.ExceptionPointers  = exceptionPointers;
435         mdei.ClientPointers = 0;
436
437 #ifdef _DEBUG
438         MINIDUMP_TYPE dumpType = MiniDumpWithFullMemory;
439 #else
440         MINIDUMP_TYPE dumpType = MiniDumpNormal;
441 #endif
442
443         ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), miniDumpFile, dumpType, &mdei, 0, 0);
444         ::CloseHandle(miniDumpFile);
445         processCrashReport(fileName.c_str());
446     }
447 }
448
449 extern "C" __declspec(dllexport) int WINAPI dllLauncherEntryPoint(HINSTANCE, HINSTANCE, LPTSTR, int nCmdShow)
450 {
451 #ifdef _CRTDBG_MAP_ALLOC
452     _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
453     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
454 #endif
455
456      // TODO: Place code here.
457     MSG msg = {0};
458     HACCEL hAccelTable;
459
460     INITCOMMONCONTROLSEX InitCtrlEx;
461
462     InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
463     InitCtrlEx.dwICC  = 0x00004000; //ICC_STANDARD_CLASSES;
464     InitCommonControlsEx(&InitCtrlEx);
465
466     _bstr_t requestedURL;
467     int argc = 0;
468     WCHAR** argv = CommandLineToArgvW(GetCommandLineW(), &argc);
469     for (int i = 1; i < argc; ++i) {
470         if (!wcsicmp(argv[i], L"--transparent"))
471             s_usesLayeredWebView = true;
472         else if (!wcsicmp(argv[i], L"--desktop"))
473             s_fullDesktop = true;
474         else if (!requestedURL)
475             requestedURL = argv[i];
476     }
477
478     // Initialize global strings
479     LoadString(hInst, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
480     LoadString(hInst, IDC_WINLAUNCHER, szWindowClass, MAX_LOADSTRING);
481     MyRegisterClass(hInst);
482
483     if (shouldUseFullDesktop())
484         computeFullDesktopFrame();
485
486     // Init COM
487     OleInitialize(NULL);
488
489     if (usesLayeredWebView()) {
490         hURLBarWnd = CreateWindow(L"EDIT", L"Type URL Here",
491                     WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOVSCROLL, 
492                     s_windowPosition.x, s_windowPosition.y + s_windowSize.cy, s_windowSize.cx, URLBAR_HEIGHT,
493                     0,
494                     0,
495                     hInst, 0);
496     } else {
497         hMainWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
498                        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, hInst, 0);
499
500         if (!hMainWnd)
501             return FALSE;
502
503         hBackButtonWnd = CreateWindow(L"BUTTON", L"<", WS_CHILD | WS_VISIBLE  | BS_TEXT, 0, 0, 0, 0, hMainWnd, 0, hInst, 0);
504         hForwardButtonWnd = CreateWindow(L"BUTTON", L">", WS_CHILD | WS_VISIBLE  | BS_TEXT, CONTROLBUTTON_WIDTH, 0, 0, 0, hMainWnd, 0, hInst, 0);
505         hURLBarWnd = CreateWindow(L"EDIT", 0, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOVSCROLL, CONTROLBUTTON_WIDTH * 2, 0, 0, 0, hMainWnd, 0, hInst, 0);
506
507         ShowWindow(hMainWnd, nCmdShow);
508         UpdateWindow(hMainWnd);
509     }
510
511     DefEditProc = reinterpret_cast<WNDPROC>(GetWindowLongPtr(hURLBarWnd, GWLP_WNDPROC));
512     DefButtonProc = reinterpret_cast<WNDPROC>(GetWindowLongPtr(hBackButtonWnd, GWLP_WNDPROC));
513     SetWindowLongPtr(hURLBarWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(EditProc));
514     SetWindowLongPtr(hBackButtonWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(BackButtonProc));
515     SetWindowLongPtr(hForwardButtonWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(ForwardButtonProc));
516
517     SetFocus(hURLBarWnd);
518
519     RECT clientRect = { s_windowPosition.x, s_windowPosition.y, s_windowPosition.x + s_windowSize.cx, s_windowPosition.y + s_windowSize.cy };
520
521     IWebPreferencesPtr tmpPreferences;
522     if (FAILED(WebKitCreateInstance(CLSID_WebPreferences, 0, IID_IWebPreferences, reinterpret_cast<void**>(&tmpPreferences.GetInterfacePtr()))))
523         goto exit;
524
525     if (FAILED(tmpPreferences->standardPreferences(&gStandardPreferences.GetInterfacePtr())))
526         goto exit;
527
528     if (!setToDefaultPreferences())
529         goto exit;
530
531     HRESULT hr = WebKitCreateInstance(CLSID_WebView, 0, IID_IWebView, reinterpret_cast<void**>(&gWebView.GetInterfacePtr()));
532     if (FAILED(hr))
533         goto exit;
534
535     hr = gWebView->QueryInterface(IID_IWebViewPrivate, reinterpret_cast<void**>(&gWebViewPrivate.GetInterfacePtr()));
536     if (FAILED(hr))
537         goto exit;
538
539     hr = WebKitCreateInstance(CLSID_WebHistory, 0, __uuidof(gWebHistory), reinterpret_cast<void**>(&gWebHistory.GetInterfacePtr()));
540     if (FAILED(hr))
541         goto exit;
542
543     gWebHost = new WinLauncherWebHost();
544     gWebHost->AddRef();
545     hr = gWebView->setFrameLoadDelegate(gWebHost);
546     if (FAILED(hr))
547         goto exit;
548
549     gPrintDelegate = new PrintWebUIDelegate;
550     gPrintDelegate->AddRef();
551     hr = gWebView->setUIDelegate(gPrintDelegate);
552     if (FAILED (hr))
553         goto exit;
554
555     gAccessibilityDelegate = new AccessibilityDelegate;
556     gAccessibilityDelegate->AddRef();
557     hr = gWebView->setAccessibilityDelegate(gAccessibilityDelegate);
558     if (FAILED (hr))
559         goto exit;
560
561     hr = gWebView->setHostWindow(reinterpret_cast<OLE_HANDLE>(hMainWnd));
562     if (FAILED(hr))
563         goto exit;
564
565     hr = gWebView->initWithFrame(clientRect, 0, 0);
566     if (FAILED(hr))
567         goto exit;
568
569     if (!requestedURL) {
570         IWebFramePtr frame;
571         hr = gWebView->mainFrame(&frame.GetInterfacePtr());
572         if (FAILED(hr))
573             goto exit;
574
575         frame->loadHTMLString(_bstr_t(defaultHTML).GetBSTR(), 0);
576     }
577
578     hr = gWebViewPrivate->setTransparent(usesLayeredWebView());
579     if (FAILED(hr))
580         goto exit;
581
582     hr = gWebViewPrivate->setUsesLayeredWindow(usesLayeredWebView());
583     if (FAILED(hr))
584         goto exit;
585
586     hr = gWebViewPrivate->viewWindow(reinterpret_cast<OLE_HANDLE*>(&gViewWindow));
587     if (FAILED(hr) || !gViewWindow)
588         goto exit;
589
590     if (usesLayeredWebView())
591         subclassForLayeredWindow();
592
593     resizeSubViews();
594
595     ShowWindow(gViewWindow, nCmdShow);
596     UpdateWindow(gViewWindow);
597
598     hAccelTable = LoadAccelerators(hInst, MAKEINTRESOURCE(IDC_WINLAUNCHER));
599
600     if (requestedURL.length())
601         loadURL(requestedURL.GetBSTR());
602
603 #pragma warning(disable:4509)
604
605     // Main message loop:
606     __try {
607         while (GetMessage(&msg, 0, 0, 0)) {
608 #if USE(CF)
609             CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
610 #endif
611             if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
612                 TranslateMessage(&msg);
613                 DispatchMessage(&msg);
614             }
615         }
616     } __except(createCrashReport(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER) { }
617
618 exit:
619     gPrintDelegate->Release();
620
621     shutDownWebKit();
622 #ifdef _CRTDBG_MAP_ALLOC
623     _CrtDumpMemoryLeaks();
624 #endif
625
626     // Shut down COM.
627     OleUninitialize();
628     
629     return static_cast<int>(msg.wParam);
630 }
631
632 ATOM MyRegisterClass(HINSTANCE hInstance)
633 {
634     WNDCLASSEX wcex;
635
636     wcex.cbSize = sizeof(WNDCLASSEX);
637
638     wcex.style          = CS_HREDRAW | CS_VREDRAW;
639     wcex.lpfnWndProc    = WndProc;
640     wcex.cbClsExtra     = 0;
641     wcex.cbWndExtra     = 0;
642     wcex.hInstance      = hInstance;
643     wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINLAUNCHER));
644     wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
645     wcex.hbrBackground  = 0;
646     wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_WINLAUNCHER);
647     wcex.lpszClassName  = szWindowClass;
648     wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
649
650     return RegisterClassEx(&wcex);
651 }
652
653 static BOOL CALLBACK AbortProc(HDC hDC, int Error)
654 {
655     MSG msg;
656     while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
657         ::TranslateMessage(&msg);
658         ::DispatchMessage(&msg);
659     }
660
661     return TRUE;
662 }
663
664 static HDC getPrinterDC()
665 {
666     PRINTDLG pdlg;
667     memset(&pdlg, 0, sizeof(PRINTDLG));
668     pdlg.lStructSize = sizeof(PRINTDLG);
669     pdlg.Flags = PD_PRINTSETUP | PD_RETURNDC;
670
671     ::PrintDlg(&pdlg);
672
673     return pdlg.hDC;
674 }
675
676 static void initDocStruct(DOCINFO* di, TCHAR* docname)
677 {
678     memset(di, 0, sizeof(DOCINFO));
679     di->cbSize = sizeof(DOCINFO);
680     di->lpszDocName = docname;
681 }
682
683 typedef _com_ptr_t<_com_IIID<IWebFramePrivate, &__uuidof(IWebFramePrivate)>> IWebFramePrivatePtr;
684
685 void PrintView(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
686 {
687     HDC printDC = getPrinterDC();
688     if (!printDC) {
689         ::MessageBoxW(0, L"Error creating printing DC", L"Error", MB_APPLMODAL | MB_OK);
690         return;
691     }
692
693     if (::SetAbortProc(printDC, AbortProc) == SP_ERROR) {
694         ::MessageBoxW(0, L"Error setting up AbortProc", L"Error", MB_APPLMODAL | MB_OK);
695         return;
696     }
697
698     IWebFramePtr frame;
699     IWebFramePrivatePtr framePrivate;
700     if (FAILED(gWebView->mainFrame(&frame.GetInterfacePtr())))
701         return;
702
703     if (FAILED(frame->QueryInterface(&framePrivate.GetInterfacePtr())))
704         return;
705
706     framePrivate->setInPrintingMode(TRUE, printDC);
707
708     UINT pageCount = 0;
709     framePrivate->getPrintedPageCount(printDC, &pageCount);
710
711     DOCINFO di;
712     initDocStruct(&di, L"WebKit Doc");
713     ::StartDoc(printDC, &di);
714
715     // FIXME: Need CoreGraphics implementation
716     void* graphicsContext = 0;
717     for (size_t page = 1; page <= pageCount; ++page) {
718         ::StartPage(printDC);
719         framePrivate->spoolPages(printDC, page, page, graphicsContext);
720         ::EndPage(printDC);
721     }
722
723     framePrivate->setInPrintingMode(FALSE, printDC);
724
725     ::EndDoc(printDC);
726     ::DeleteDC(printDC);
727 }
728
729 static void ToggleMenuItem(HWND hWnd, UINT menuID)
730 {
731     HMENU menu = ::GetMenu(hWnd);
732
733     MENUITEMINFO info;
734     ::memset(&info, 0x00, sizeof(info));
735     info.cbSize = sizeof(info);
736     info.fMask = MIIM_STATE;
737
738     if (!::GetMenuItemInfo(menu, menuID, FALSE, &info))
739         return;
740
741     BOOL newState = !(info.fState & MFS_CHECKED);
742
743     if (!gStandardPreferences || !gPrefsPrivate)
744         return;
745
746     switch (menuID) {
747     case IDM_AVFOUNDATION:
748         gStandardPreferences->setAVFoundationEnabled(newState);
749         break;
750     case IDM_ACC_COMPOSITING:
751         gPrefsPrivate->setAcceleratedCompositingEnabled(newState);
752         break;
753     case IDM_WK_FULLSCREEN:
754         gPrefsPrivate->setFullScreenEnabled(newState);
755         break;
756     case IDM_COMPOSITING_BORDERS:
757         gPrefsPrivate->setShowDebugBorders(newState);
758         gPrefsPrivate->setShowRepaintCounter(newState);
759         break;
760     case IDM_DISABLE_IMAGES:
761         gStandardPreferences->setLoadsImagesAutomatically(!newState);
762         break;
763     case IDM_DISABLE_STYLES:
764         gPrefsPrivate->setAuthorAndUserStylesEnabled(!newState);
765         break;
766     case IDM_DISABLE_JAVASCRIPT:
767         gStandardPreferences->setJavaScriptEnabled(!newState);
768         break;
769     case IDM_DISABLE_LOCAL_FILE_RESTRICTIONS:
770         gPrefsPrivate->setAllowUniversalAccessFromFileURLs(newState);
771         gPrefsPrivate->setAllowFileAccessFromFileURLs(newState);
772         break;
773     }
774
775     info.fState = (newState) ? MFS_CHECKED : MFS_UNCHECKED;
776
777     ::SetMenuItemInfo(menu, menuID, FALSE, &info);
778 }
779
780 static void LaunchInspector(HWND hwnd)
781 {
782     if (!gWebViewPrivate)
783         return;
784
785     if (!SUCCEEDED(gWebViewPrivate->inspector(&gInspector.GetInterfacePtr())))
786         return;
787
788     gInspector->show();
789 }
790
791 static void NavigateForwardOrBackward(HWND hWnd, UINT menuID)
792 {
793     if (!gWebView)
794         return;
795
796     BOOL wentBackOrForward = FALSE;
797     if (IDM_HISTORY_FORWARD == menuID)
798         gWebView->goForward(&wentBackOrForward);
799     else
800         gWebView->goBack(&wentBackOrForward);
801 }
802
803 static void NavigateToHistory(HWND hWnd, UINT menuID)
804 {
805     if (!gWebView)
806         return;
807
808     int historyEntry = menuID - IDM_HISTORY_LINK0;
809     if (historyEntry > gHistoryItems.size())
810         return;
811
812     IWebHistoryItemPtr desiredHistoryItem = gHistoryItems[historyEntry];
813     if (!desiredHistoryItem)
814         return;
815
816     BOOL succeeded = FALSE;
817     gWebView->goToBackForwardItem(desiredHistoryItem, &succeeded);
818
819     _bstr_t frameURL;
820     desiredHistoryItem->URLString(frameURL.GetAddress());
821
822     ::SendMessage(hURLBarWnd, (UINT)WM_SETTEXT, 0, (LPARAM)frameURL.GetBSTR());
823 }
824
825 static const int dragBarHeight = 30;
826
827 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
828 {
829     WNDPROC parentProc = usesLayeredWebView() ? DefWebKitProc : DefWindowProc;
830
831     switch (message) {
832     case WM_NCHITTEST:
833         if (usesLayeredWebView()) {
834             RECT window;
835             ::GetWindowRect(hWnd, &window);
836             // For testing our transparent window, we need a region to use as a handle for
837             // dragging. The right way to do this would be to query the web view to see what's
838             // under the mouse. However, for testing purposes we just use an arbitrary
839             // 30 pixel band at the top of the view as an arbitrary gripping location.
840             //
841             // When we are within this bad, return HT_CAPTION to tell Windows we want to
842             // treat this region as if it were the title bar on a normal window.
843             int y = HIWORD(lParam);
844
845             if ((y > window.top) && (y < window.top + dragBarHeight))
846                 return HTCAPTION;
847         }
848         return CallWindowProc(parentProc, hWnd, message, wParam, lParam);
849     case WM_COMMAND: {
850         int wmId = LOWORD(wParam);
851         int wmEvent = HIWORD(wParam);
852         if (wmId >= IDM_HISTORY_LINK0 && wmId <= IDM_HISTORY_LINK9) {
853             NavigateToHistory(hWnd, wmId);
854             break;
855         }
856         // Parse the menu selections:
857         switch (wmId) {
858         case IDM_ABOUT:
859             DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
860             break;
861         case IDM_EXIT:
862             DestroyWindow(hWnd);
863             break;
864         case IDM_PRINT:
865             PrintView(hWnd, message, wParam, lParam);
866             break;
867         case IDM_WEB_INSPECTOR:
868             LaunchInspector(hWnd);
869             break;
870         case IDM_HISTORY_BACKWARD:
871         case IDM_HISTORY_FORWARD:
872             NavigateForwardOrBackward(hWnd, wmId);
873             break;
874         case IDM_AVFOUNDATION:
875         case IDM_ACC_COMPOSITING:
876         case IDM_WK_FULLSCREEN:
877         case IDM_COMPOSITING_BORDERS:
878         case IDM_DISABLE_IMAGES:
879         case IDM_DISABLE_STYLES:
880         case IDM_DISABLE_JAVASCRIPT:
881         case IDM_DISABLE_LOCAL_FILE_RESTRICTIONS:
882             ToggleMenuItem(hWnd, wmId);
883             break;
884         default:
885             return CallWindowProc(parentProc, hWnd, message, wParam, lParam);
886         }
887         }
888         break;
889     case WM_DESTROY:
890 #if USE(CF)
891         CFRunLoopStop(CFRunLoopGetMain());
892 #endif
893         PostQuitMessage(0);
894         break;
895     case WM_SIZE:
896         if (!gWebView || usesLayeredWebView())
897            return CallWindowProc(parentProc, hWnd, message, wParam, lParam);
898
899         resizeSubViews();
900         break;
901     default:
902         return CallWindowProc(parentProc, hWnd, message, wParam, lParam);
903     }
904
905     return 0;
906 }
907
908 LRESULT CALLBACK EditProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
909 {
910     switch (message) {
911     case WM_CHAR:
912         if (wParam == 13) { // Enter Key
913             wchar_t strPtr[INTERNET_MAX_URL_LENGTH];
914             *((LPWORD)strPtr) = INTERNET_MAX_URL_LENGTH; 
915             int strLen = SendMessage(hDlg, EM_GETLINE, 0, (LPARAM)strPtr);
916
917             strPtr[strLen] = 0;
918             _bstr_t bstr(strPtr);
919             loadURL(bstr.GetBSTR());
920
921             return 0;
922         } 
923     default:
924         return CallWindowProc(DefEditProc, hDlg, message, wParam, lParam);
925     }
926 }
927
928 LRESULT CALLBACK BackButtonProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
929 {
930     BOOL wentBack = FALSE;
931     switch (message) {
932     case WM_LBUTTONUP:
933         gWebView->goBack(&wentBack);
934     default:
935         return CallWindowProc(DefButtonProc, hDlg, message, wParam, lParam);
936     }
937 }
938
939 LRESULT CALLBACK ForwardButtonProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
940 {
941     BOOL wentForward = FALSE;
942     switch (message) {
943     case WM_LBUTTONUP:
944         gWebView->goForward(&wentForward);
945     default:
946         return CallWindowProc(DefButtonProc, hDlg, message, wParam, lParam);
947     }
948 }
949
950 // Message handler for about box.
951 INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
952 {
953     UNREFERENCED_PARAMETER(lParam);
954     switch (message) {
955     case WM_INITDIALOG:
956         return (INT_PTR)TRUE;
957
958     case WM_COMMAND:
959         if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
960             EndDialog(hDlg, LOWORD(wParam));
961             return (INT_PTR)TRUE;
962         }
963         break;
964     }
965     return (INT_PTR)FALSE;
966 }
967
968 static void loadURL(BSTR passedURL)
969 {
970     _bstr_t urlBStr(passedURL);
971     if (!!urlBStr && (::PathFileExists(urlBStr) || ::PathIsUNC(urlBStr))) {
972         TCHAR fileURL[INTERNET_MAX_URL_LENGTH];
973         DWORD fileURLLength = sizeof(fileURL)/sizeof(fileURL[0]);
974
975         if (SUCCEEDED(::UrlCreateFromPath(urlBStr, fileURL, &fileURLLength, 0)))
976             urlBStr = fileURL;
977     }
978
979     IWebFramePtr frame;
980     HRESULT hr = gWebView->mainFrame(&frame.GetInterfacePtr());
981     if (FAILED(hr))
982         return;
983
984     IWebMutableURLRequestPtr request;
985     hr = WebKitCreateInstance(CLSID_WebMutableURLRequest, 0, IID_IWebMutableURLRequest, (void**)&request);
986     if (FAILED(hr))
987         return;
988
989     hr = request->initWithURL(wcsstr(static_cast<wchar_t*>(urlBStr), L"://") ? urlBStr : _bstr_t(L"http://") + urlBStr, WebURLRequestUseProtocolCachePolicy, 60);
990     if (FAILED(hr))
991         return;
992
993     _bstr_t methodBStr(L"GET");
994     hr = request->setHTTPMethod(methodBStr);
995     if (FAILED(hr))
996         return;
997
998     hr = frame->loadRequest(request);
999     if (FAILED(hr))
1000         return;
1001
1002     SetFocus(gViewWindow);
1003 }