| 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 |