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
3 // found in the LICENSE file.
9 #include "base/win/scoped_variant.h"
10 #include "chrome/installer/util/html_dialog.h"
12 #pragma comment(lib, "urlmon.lib")
16 // Windows implementation of the HTML dialog class. The main danger with
17 // using the IE embedded control as a child window of a custom window is that
18 // it still contains too much browser functionality, allowing the user to do
19 // things that are not expected of a plain dialog. ShowHTMLDialog API solves
20 // that problem but gives us a not very customizable frame. We solve that
21 // using hooks to end up with a robust dialog at the expense of having to do
22 // the buttons in html itself, like so:
24 // <form onsubmit="submit_it(this); return false;">
25 // <input name="accept" type="checkbox" /> My cool option
26 // <input name="submit" type="submit" value="[accept]" />
29 // function submit_it(f) {
30 // if (f.accept.checked) {
31 // window.returnValue = 1; <-- this matches HTML_DLG_ACCEPT
33 // window.returnValue = 2; <-- this matches HTML_DLG_DECLINE
38 // Note that on the submit handler you need to set window.returnValue to one of
39 // the values of DialogResult and call window.close().
41 class HTMLDialogWin
: public HTMLDialog
{
43 HTMLDialogWin(const std::wstring
& url
, const std::wstring
& param
)
44 : url_(url
), param_(param
) {
46 mshtml_
= LoadLibrary(L
"MSHTML.DLL");
49 virtual DialogResult
ShowModal(void* parent_window
,
50 CustomizationCallback
* callback
) {
51 int result
= HTML_DLG_DECLINE
;
52 if (!InternalDoDialog(callback
, &result
))
53 return HTML_DLG_ERROR
;
54 return static_cast<DialogResult
>(result
);
57 virtual std::wstring
GetExtraResult() {
62 bool InternalDoDialog(CustomizationCallback
* callback
, int* result
);
63 static LRESULT CALLBACK
MsgFilter(int code
, WPARAM wParam
, LPARAM lParam
);
68 static HINSTANCE mshtml_
;
69 static CustomizationCallback
* callback_
;
70 std::wstring extra_result_
;
73 HTMLDialog
* CreateNativeHTMLDialog(const std::wstring
& url
,
74 const std::wstring
& param
) {
75 return new HTMLDialogWin(url
, param
);
78 HHOOK
HTMLDialogWin::hook_
= NULL
;
79 HINSTANCE
HTMLDialogWin::mshtml_
= NULL
;
80 HTMLDialogWin::CustomizationCallback
* HTMLDialogWin::callback_
= NULL
;
82 // This hook function gets called for messages bound to the windows that
83 // ShowHTMLDialog creates. We tell apart the top window because it has the
85 LRESULT
HTMLDialogWin::MsgFilter(int code
, WPARAM wParam
, LPARAM lParam
) {
86 static bool tweak_window
= true;
87 if (lParam
&& tweak_window
) {
88 HWND target_window
= reinterpret_cast<MSG
*>(lParam
)->hwnd
;
90 LONG_PTR style
= ::GetWindowLongPtrW(target_window
, GWL_STYLE
);
91 if (style
& WS_SYSMENU
) {
93 callback_
->OnBeforeDisplay(target_window
);
97 // Always call the next hook in the chain.
98 return ::CallNextHookEx(hook_
, code
, wParam
, lParam
);
101 bool HTMLDialogWin::InternalDoDialog(CustomizationCallback
* callback
,
105 SHOWHTMLDIALOGFN
* show_html_dialog
=
106 reinterpret_cast<SHOWHTMLDIALOGFN
*>(
107 GetProcAddress(mshtml_
, "ShowHTMLDialog"));
108 if (!show_html_dialog
)
111 IMoniker
*url_moniker
= NULL
;
112 ::CreateURLMonikerEx(NULL
, url_
.c_str(), &url_moniker
, URL_MK_UNIFORM
);
116 wchar_t* extra_args
= NULL
;
118 callback
->OnBeforeCreation(&extra_args
);
119 // Sets a windows hook for this thread only.
120 hook_
= ::SetWindowsHookEx(WH_GETMESSAGE
, MsgFilter
, NULL
,
121 GetCurrentThreadId());
123 callback_
= callback
;
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());
131 ::VariantInit(&v_result
);
133 // Creates the window with the embedded IE control in a modal loop.
134 HRESULT hr
= show_html_dialog(NULL
,
136 dialog_args
.AsInput(),
139 url_moniker
->Release();
141 if (v_result
.vt
== VT_I4
) {
142 *result
= v_result
.intVal
;
143 } else if (v_result
.vt
== VT_BSTR
) {
144 *result
= HTML_DLG_EXTRA
;
145 extra_result_
.assign(v_result
.bstrVal
, SysStringLen(v_result
.bstrVal
));
148 ::VariantClear(&v_result
);
151 ::UnhookWindowsHookEx(hook_
);
155 return SUCCEEDED(hr
);
158 // EulaHTMLDialog implementation ---------------------------------------------
160 void EulaHTMLDialog::Customizer::OnBeforeCreation(wchar_t** extra
) {
163 // The customization of the window consists in removing the close button and
164 // replacing the existing 'e' icon with the standard informational icon.
165 void EulaHTMLDialog::Customizer::OnBeforeDisplay(void* window
) {
168 HWND top_window
= static_cast<HWND
>(window
);
169 LONG_PTR style
= ::GetWindowLongPtrW(top_window
, GWL_STYLE
);
170 ::SetWindowLongPtrW(top_window
, GWL_STYLE
, style
& ~WS_SYSMENU
);
171 HICON ico
= ::LoadIcon(NULL
, IDI_INFORMATION
);
172 ::SendMessageW(top_window
, WM_SETICON
, ICON_SMALL
,
173 reinterpret_cast<LPARAM
>(ico
));
176 EulaHTMLDialog::EulaHTMLDialog(const std::wstring
& file
,
177 const std::wstring
& param
) {
178 dialog_
= CreateNativeHTMLDialog(file
, param
);
181 EulaHTMLDialog::~EulaHTMLDialog() {
185 EulaHTMLDialog::Outcome
EulaHTMLDialog::ShowModal() {
186 Customizer customizer
;
187 HTMLDialog::DialogResult dr
= dialog_
->ShowModal(NULL
, &customizer
);
188 if (HTMLDialog::HTML_DLG_ACCEPT
== dr
)
189 return EulaHTMLDialog::ACCEPTED
;
190 else if (HTMLDialog::HTML_DLG_EXTRA
== dr
)
191 return EulaHTMLDialog::ACCEPTED_OPT_IN
;
193 return EulaHTMLDialog::REJECTED
;
196 } // namespace installer