OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <windows.h> | 5 #include <windows.h> |
| 6 #include <mshtmhst.h> |
6 #include <urlmon.h> | 7 #include <urlmon.h> |
7 | 8 |
| 9 #include "base/win/scoped_variant.h" |
8 #include "chrome/installer/util/html_dialog.h" | 10 #include "chrome/installer/util/html_dialog.h" |
9 | 11 |
10 #pragma comment(lib, "urlmon.lib") | 12 #pragma comment(lib, "urlmon.lib") |
11 | 13 |
12 namespace { | |
13 // Signature of MSHTML.DLL ShowHTMLDlg. | |
14 typedef HRESULT (CALLBACK *ShowHTMLDlg)(HWND parent_hwnd, | |
15 IMoniker *moniker, | |
16 VARIANT *in_args, | |
17 TCHAR *options, | |
18 VARIANT *out_args); | |
19 } // namespace. | |
20 | |
21 namespace installer { | 14 namespace installer { |
22 | 15 |
23 // Windows implementation of the HTML dialog class. The main danger with | 16 // Windows implementation of the HTML dialog class. The main danger with |
24 // using the IE embedded control as a child window of a custom window is that | 17 // using the IE embedded control as a child window of a custom window is that |
25 // it still contains too much browser functionality, allowing the user to do | 18 // it still contains too much browser functionality, allowing the user to do |
26 // things that are not expected of a plain dialog. ShowHTMLDialog API solves | 19 // things that are not expected of a plain dialog. ShowHTMLDialog API solves |
27 // that problem but gives us a not very customizable frame. We solve that | 20 // that problem but gives us a not very customizable frame. We solve that |
28 // using hooks to end up with a robust dialog at the expense of having to do | 21 // using hooks to end up with a robust dialog at the expense of having to do |
29 // the buttons in html itself, like so: | 22 // the buttons in html itself, like so: |
30 // | 23 // |
31 // <form onsubmit="submit_it(this); return false;"> | 24 // <form onsubmit="submit_it(this); return false;"> |
32 // <input name="accept" type="checkbox" /> My cool option | 25 // <input name="accept" type="checkbox" /> My cool option |
33 // <input name="submit" type="submit" value="[accept]" /> | 26 // <input name="submit" type="submit" value="[accept]" /> |
34 // </form> | 27 // </form> |
35 // | 28 // |
36 // function submit_it(f) { | 29 // function submit_it(f) { |
37 // if (f.accept.checked) { | 30 // if (f.accept.checked) { |
38 // window.returnValue = 1; <-- this matches HTML_DLG_ACCEPT | 31 // window.returnValue = 1; <-- this matches HTML_DLG_ACCEPT |
39 // } else { | 32 // } else { |
40 // window.returnValue = 2; <-- this matches HTML_DLG_DECLINE | 33 // window.returnValue = 2; <-- this matches HTML_DLG_DECLINE |
41 // } | 34 // } |
42 // window.close(); | 35 // window.close(); |
43 // } | 36 // } |
44 // | 37 // |
45 // Note that on the submit handler you need to set window.returnValue to one of | 38 // Note that on the submit handler you need to set window.returnValue to one of |
46 // the values of DialogResult and call window.close(). | 39 // the values of DialogResult and call window.close(). |
47 | 40 |
48 class HTMLDialogWin : public HTMLDialog { | 41 class HTMLDialogWin : public HTMLDialog { |
49 public: | 42 public: |
50 explicit HTMLDialogWin(const std::wstring& url) : url_(url) { | 43 HTMLDialogWin(const std::wstring& url, const std::wstring& param) |
| 44 : url_(url), param_(param) { |
51 if (!mshtml_) | 45 if (!mshtml_) |
52 mshtml_ = LoadLibrary(L"MSHTML.DLL"); | 46 mshtml_ = LoadLibrary(L"MSHTML.DLL"); |
53 } | 47 } |
54 | 48 |
55 virtual DialogResult ShowModal(void* parent_window, | 49 virtual DialogResult ShowModal(void* parent_window, |
56 CustomizationCallback* callback) { | 50 CustomizationCallback* callback) { |
57 int result = HTML_DLG_DECLINE; | 51 int result = HTML_DLG_DECLINE; |
58 if (!InternalDoDialog(callback, &result)) | 52 if (!InternalDoDialog(callback, &result)) |
59 return HTML_DLG_ERROR; | 53 return HTML_DLG_ERROR; |
60 return static_cast<DialogResult>(result); | 54 return static_cast<DialogResult>(result); |
61 } | 55 } |
62 | 56 |
63 // TODO(cpu): Not yet implemented. | 57 // TODO(cpu): Not yet implemented. |
64 virtual std::wstring GetExtraResult() { | 58 virtual std::wstring GetExtraResult() { |
65 return std::wstring(); | 59 return std::wstring(); |
66 } | 60 } |
67 | 61 |
68 private: | 62 private: |
69 bool InternalDoDialog(CustomizationCallback* callback, int* result); | 63 bool InternalDoDialog(CustomizationCallback* callback, int* result); |
70 static LRESULT CALLBACK MsgFilter(int code, WPARAM wParam, LPARAM lParam); | 64 static LRESULT CALLBACK MsgFilter(int code, WPARAM wParam, LPARAM lParam); |
71 | 65 |
72 std::wstring url_; | 66 std::wstring url_; |
| 67 std::wstring param_; |
73 static HHOOK hook_; | 68 static HHOOK hook_; |
74 static HINSTANCE mshtml_; | 69 static HINSTANCE mshtml_; |
75 static CustomizationCallback* callback_; | 70 static CustomizationCallback* callback_; |
76 }; | 71 }; |
77 | 72 |
78 HTMLDialog* CreateNativeHTMLDialog(const std::wstring& url) { | 73 HTMLDialog* CreateNativeHTMLDialog(const std::wstring& url, |
79 return new HTMLDialogWin(url); | 74 const std::wstring& param) { |
| 75 return new HTMLDialogWin(url, param); |
80 } | 76 } |
81 | 77 |
82 HHOOK HTMLDialogWin::hook_ = NULL; | 78 HHOOK HTMLDialogWin::hook_ = NULL; |
83 HINSTANCE HTMLDialogWin::mshtml_ = NULL; | 79 HINSTANCE HTMLDialogWin::mshtml_ = NULL; |
84 HTMLDialogWin::CustomizationCallback* HTMLDialogWin::callback_ = NULL; | 80 HTMLDialogWin::CustomizationCallback* HTMLDialogWin::callback_ = NULL; |
85 | 81 |
86 // This hook function gets called for messages bound to the windows that | 82 // This hook function gets called for messages bound to the windows that |
87 // ShowHTMLDialog creates. We tell apart the top window because it has the | 83 // ShowHTMLDialog creates. We tell apart the top window because it has the |
88 // system menu style. | 84 // system menu style. |
89 LRESULT HTMLDialogWin::MsgFilter(int code, WPARAM wParam, LPARAM lParam) { | 85 LRESULT HTMLDialogWin::MsgFilter(int code, WPARAM wParam, LPARAM lParam) { |
90 static bool tweak_window = true; | 86 static bool tweak_window = true; |
91 if (lParam && tweak_window) { | 87 if (lParam && tweak_window) { |
92 HWND target_window = reinterpret_cast<MSG*>(lParam)->hwnd; | 88 HWND target_window = reinterpret_cast<MSG*>(lParam)->hwnd; |
93 if (target_window) { | 89 if (target_window) { |
94 LONG_PTR style = ::GetWindowLongPtrW(target_window, GWL_STYLE); | 90 LONG_PTR style = ::GetWindowLongPtrW(target_window, GWL_STYLE); |
95 if (style & WS_SYSMENU) { | 91 if (style & WS_SYSMENU) { |
96 tweak_window = false; | 92 tweak_window = false; |
97 callback_->OnBeforeDisplay(target_window); | 93 callback_->OnBeforeDisplay(target_window); |
98 } | 94 } |
99 } | 95 } |
100 } | 96 } |
101 // Always call the next hook in the chain. | 97 // Always call the next hook in the chain. |
102 return ::CallNextHookEx(hook_, code, wParam, lParam); | 98 return ::CallNextHookEx(hook_, code, wParam, lParam); |
103 } | 99 } |
104 | 100 |
105 bool HTMLDialogWin::InternalDoDialog(CustomizationCallback* callback, | 101 bool HTMLDialogWin::InternalDoDialog(CustomizationCallback* callback, |
106 int* result) { | 102 int* result) { |
107 if (!mshtml_) | 103 if (!mshtml_) |
108 return false; | 104 return false; |
109 ShowHTMLDlg show_html_dialog = | 105 SHOWHTMLDIALOGFN* show_html_dialog = |
110 reinterpret_cast<ShowHTMLDlg>(GetProcAddress(mshtml_, "ShowHTMLDialog")); | 106 reinterpret_cast<SHOWHTMLDIALOGFN*>( |
| 107 GetProcAddress(mshtml_, "ShowHTMLDialog")); |
111 if (!show_html_dialog) | 108 if (!show_html_dialog) |
112 return false; | 109 return false; |
113 | 110 |
114 IMoniker *url_moniker = NULL; | 111 IMoniker *url_moniker = NULL; |
115 ::CreateURLMoniker(NULL, url_.c_str(), &url_moniker); | 112 ::CreateURLMonikerEx(NULL, url_.c_str(), &url_moniker, URL_MK_UNIFORM); |
116 if (!url_moniker) | 113 if (!url_moniker) |
117 return false; | 114 return false; |
118 | 115 |
119 wchar_t* extra_args = NULL; | 116 wchar_t* extra_args = NULL; |
120 if (callback) { | 117 if (callback) { |
121 callback->OnBeforeCreation(reinterpret_cast<void**>(&extra_args)); | 118 callback->OnBeforeCreation(reinterpret_cast<void**>(&extra_args)); |
122 // Sets a windows hook for this thread only. | 119 // Sets a windows hook for this thread only. |
123 hook_ = ::SetWindowsHookEx(WH_GETMESSAGE, MsgFilter, NULL, | 120 hook_ = ::SetWindowsHookEx(WH_GETMESSAGE, MsgFilter, NULL, |
124 GetCurrentThreadId()); | 121 GetCurrentThreadId()); |
125 if (hook_) | 122 if (hook_) |
126 callback_ = callback; | 123 callback_ = callback; |
127 } | 124 } |
128 | 125 |
| 126 // Pass our parameter to the dialog in the dialogArguments property of |
| 127 // the window object. |
| 128 base::win::ScopedVariant dialog_args(param_.c_str()); |
| 129 |
129 VARIANT v_result; | 130 VARIANT v_result; |
130 ::VariantInit(&v_result); | 131 ::VariantInit(&v_result); |
131 | 132 |
132 // Creates the window with the embedded IE control in a modal loop. | 133 // Creates the window with the embedded IE control in a modal loop. |
133 HRESULT hr = show_html_dialog(NULL, url_moniker, NULL, extra_args, &v_result); | 134 HRESULT hr = show_html_dialog(NULL, |
| 135 url_moniker, |
| 136 dialog_args.AsInput(), |
| 137 extra_args, |
| 138 &v_result); |
134 url_moniker->Release(); | 139 url_moniker->Release(); |
135 | 140 |
136 if (v_result.vt == VT_I4) | 141 if (v_result.vt == VT_I4) |
137 *result = v_result.intVal; | 142 *result = v_result.intVal; |
138 ::VariantClear(&v_result); | 143 ::VariantClear(&v_result); |
139 | 144 |
140 if (hook_) { | 145 if (hook_) { |
141 ::UnhookWindowsHookEx(hook_); | 146 ::UnhookWindowsHookEx(hook_); |
142 callback_ = NULL; | 147 callback_ = NULL; |
143 hook_ = NULL; | 148 hook_ = NULL; |
(...skipping 12 matching lines...) Expand all Loading... |
156 if (!window) | 161 if (!window) |
157 return; | 162 return; |
158 HWND top_window = static_cast<HWND>(window); | 163 HWND top_window = static_cast<HWND>(window); |
159 LONG_PTR style = ::GetWindowLongPtrW(top_window, GWL_STYLE); | 164 LONG_PTR style = ::GetWindowLongPtrW(top_window, GWL_STYLE); |
160 ::SetWindowLongPtrW(top_window, GWL_STYLE, style & ~WS_SYSMENU); | 165 ::SetWindowLongPtrW(top_window, GWL_STYLE, style & ~WS_SYSMENU); |
161 HICON ico = ::LoadIcon(NULL, IDI_INFORMATION); | 166 HICON ico = ::LoadIcon(NULL, IDI_INFORMATION); |
162 ::SendMessageW(top_window, WM_SETICON, ICON_SMALL, | 167 ::SendMessageW(top_window, WM_SETICON, ICON_SMALL, |
163 reinterpret_cast<LPARAM>(ico)); | 168 reinterpret_cast<LPARAM>(ico)); |
164 } | 169 } |
165 | 170 |
166 EulaHTMLDialog::EulaHTMLDialog(const std::wstring& file) { | 171 EulaHTMLDialog::EulaHTMLDialog(const std::wstring& file, |
167 dialog_ = CreateNativeHTMLDialog(file); | 172 const std::wstring& param) { |
| 173 dialog_ = CreateNativeHTMLDialog(file, param); |
168 } | 174 } |
169 | 175 |
170 EulaHTMLDialog::~EulaHTMLDialog() { | 176 EulaHTMLDialog::~EulaHTMLDialog() { |
171 delete dialog_; | 177 delete dialog_; |
172 } | 178 } |
173 | 179 |
174 EulaHTMLDialog::Outcome EulaHTMLDialog::ShowModal() { | 180 EulaHTMLDialog::Outcome EulaHTMLDialog::ShowModal() { |
175 Customizer customizer; | 181 Customizer customizer; |
176 HTMLDialog::DialogResult dr = dialog_->ShowModal(NULL, &customizer); | 182 HTMLDialog::DialogResult dr = dialog_->ShowModal(NULL, &customizer); |
177 if (HTMLDialog::HTML_DLG_ACCEPT == dr) | 183 if (HTMLDialog::HTML_DLG_ACCEPT == dr) |
178 return EulaHTMLDialog::ACCEPTED; | 184 return EulaHTMLDialog::ACCEPTED; |
179 else if (HTMLDialog::HTML_DLG_EXTRA == dr) | 185 else if (HTMLDialog::HTML_DLG_EXTRA == dr) |
180 return EulaHTMLDialog::ACCEPTED_OPT_IN; | 186 return EulaHTMLDialog::ACCEPTED_OPT_IN; |
181 else | 187 else |
182 return EulaHTMLDialog::REJECTED; | 188 return EulaHTMLDialog::REJECTED; |
183 } | 189 } |
184 | 190 |
185 } // namespace installer | 191 } // namespace installer |
OLD | NEW |