Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(434)

Unified Diff: remoting/host/it2me/it2me_confirmation_dialog_win.cc

Issue 2326553003: Adding a Confirmation dialog for It2Me on Windows (Closed)
Patch Set: Addressing CR feedback Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « remoting/host/it2me/it2me_confirmation_dialog_mac.cc ('k') | remoting/host/win/core.rc.jinja2 » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: remoting/host/it2me/it2me_confirmation_dialog_win.cc
diff --git a/remoting/host/it2me/it2me_confirmation_dialog_win.cc b/remoting/host/it2me/it2me_confirmation_dialog_win.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4e8453f91e571f866c2b1e68fb7e8ced9ad3c9bf
--- /dev/null
+++ b/remoting/host/it2me/it2me_confirmation_dialog_win.cc
@@ -0,0 +1,216 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+#include <commctrl.h>
+
+#include <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/i18n/message_formatter.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "remoting/host/it2me/it2me_confirmation_dialog.h"
+#include "remoting/host/win/core_resource.h"
+
+namespace remoting {
+
+namespace {
+
+// Time to wait before closing the dialog and cancelling the connection.
+const int kDialogTimeoutMs = 60 * 1000;
+
+const HRESULT kTimeoutErrorCode = E_ABORT;
+
+// Loads an embedded string resource from the specified module.
+bool LoadStringResource(HMODULE resource_module,
+ int resource_id,
+ base::string16* string) {
+ DCHECK(resource_module);
+ DCHECK(string);
+
+ string->clear();
+
+ const wchar_t* string_resource = nullptr;
+ int string_length = LoadStringW(resource_module, resource_id,
+ reinterpret_cast<wchar_t*>(&string_resource),
+ /*nBufferMax=*/0);
+ if (string_length <= 0) {
+ PLOG(ERROR) << "LoadStringW() failed";
+ return false;
+ }
+
+ string->append(string_resource, string_length);
+ return true;
+}
+
+class It2MeConfirmationDialogWin : public It2MeConfirmationDialog {
+ public:
+ It2MeConfirmationDialogWin();
+ ~It2MeConfirmationDialogWin() override;
+
+ static HRESULT CALLBACK TaskDialogCallbackProc(HWND hwnd,
+ UINT notification,
+ WPARAM w_param,
+ LPARAM l_param,
+ LONG_PTR ref_data);
+
+ // It2MeConfirmationDialog implementation.
+ void Show(const std::string& remote_user_email,
+ const ResultCallback& callback) override;
+
+ private:
+ // Tracks whether the dialog was in the foreground the last time we checked.
+ // Default to true so we will attempt to bring it back if it starts in the
+ // background for some reason.
+ bool is_foreground_window_ = true;
+
+ DISALLOW_COPY_AND_ASSIGN(It2MeConfirmationDialogWin);
+};
+
+It2MeConfirmationDialogWin::It2MeConfirmationDialogWin() {}
+
+It2MeConfirmationDialogWin::~It2MeConfirmationDialogWin() {}
+
+void It2MeConfirmationDialogWin::Show(const std::string& remote_user_email,
+ const ResultCallback& callback) {
+ DCHECK(!remote_user_email.empty());
+ DCHECK(!callback.is_null());
+
+ // Default to a cancelled state. We only accept the connection if the user
+ // explicitly allows it.
+ Result result = Result::CANCEL;
+
+ // |resource_module| does not need to be freed as GetModuleHandle() does not
+ // increment the refcount for the module. This DLL is not unloaded until the
+ // process exits so using a stored handle is safe.
+ HMODULE resource_module = GetModuleHandle(L"remoting_core.dll");
+ if (resource_module == nullptr) {
+ PLOG(ERROR) << "GetModuleHandle() failed";
+ callback.Run(result);
+ return;
+ }
+
+ base::string16 title_text;
+ if (!LoadStringResource(resource_module, IDS_PRODUCT_NAME, &title_text)) {
+ LOG(ERROR) << "Failed to load title text for confirmation dialog.";
+ callback.Run(result);
+ return;
+ }
+
+ base::string16 message_text;
+ if (!LoadStringResource(resource_module,
+ IDS_SHARE_CONFIRM_DIALOG_MESSAGE_WITH_USERNAME,
+ &message_text)) {
+ LOG(ERROR) << "Failed to load message text for confirmation dialog.";
+ callback.Run(result);
+ return;
+ }
+ message_text = base::i18n::MessageFormatter::FormatWithNumberedArgs(
+ message_text, base::UTF8ToUTF16(remote_user_email));
+
+ base::string16 share_button_text;
+ if (!LoadStringResource(resource_module, IDS_SHARE_CONFIRM_DIALOG_CONFIRM,
+ &share_button_text)) {
+ LOG(ERROR) << "Failed to load share button text for confirmation dialog.";
+ callback.Run(result);
+ return;
+ }
+
+ base::string16 decline_button_text;
+ if (!LoadStringResource(resource_module, IDS_SHARE_CONFIRM_DIALOG_DECLINE,
+ &decline_button_text)) {
+ LOG(ERROR) << "Failed to load decline button text for confirmation dialog.";
+ callback.Run(result);
+ return;
+ }
+
+ TASKDIALOG_BUTTON dialog_buttons[] = {
+ {IDYES, share_button_text.c_str()}, {IDNO, decline_button_text.c_str()},
+ };
+
+ TASKDIALOGCONFIG dialog_config = {0};
+ dialog_config.cbSize = sizeof(dialog_config);
+ dialog_config.hInstance = resource_module;
+ dialog_config.pszWindowTitle = title_text.c_str();
+ dialog_config.pszMainInstruction = message_text.c_str();
+ dialog_config.pszMainIcon = MAKEINTRESOURCE(IDI_CHROME_REMOTE_DESKTOP);
+ dialog_config.dwFlags = TDF_CALLBACK_TIMER;
+ dialog_config.pfCallback = &TaskDialogCallbackProc;
+ dialog_config.lpCallbackData = reinterpret_cast<LONG_PTR>(this);
+ dialog_config.cButtons = ARRAYSIZE(dialog_buttons);
+ dialog_config.pButtons = dialog_buttons;
+ dialog_config.nDefaultButton = IDNO;
+
+ int button_result = 0;
+ HRESULT hr = TaskDialogIndirect(&dialog_config, &button_result,
+ /*pnRadioButton=*/nullptr,
+ /*pfVerificationFlagChecked=*/nullptr);
+ if (FAILED(hr)) {
+ if (hr == kTimeoutErrorCode) {
+ LOG(INFO) << "TaskDialog timed out.";
+ } else {
+ LOG(ERROR) << "TaskDialogIndirect() Failed: 0x" << std::hex << hr;
+ }
+
+ callback.Run(result);
+ return;
+ }
+
+ if (button_result == IDYES) {
+ // Only accept the connection if the user chose 'share'.
+ result = Result::OK;
+ }
+
+ callback.Run(result);
+}
+
+HRESULT CALLBACK
+It2MeConfirmationDialogWin::TaskDialogCallbackProc(HWND hwnd,
+ UINT notification,
+ WPARAM w_param,
+ LPARAM l_param,
+ LONG_PTR ref_data) {
+ if (notification == TDN_TIMER) {
+ if (w_param >= kDialogTimeoutMs) {
+ // Close the dialog window if we have reached the timeout.
+ return kTimeoutErrorCode;
+ }
+
+ // Ensure the window is visible before checking if it is in the foreground.
+ if (!IsWindowVisible(hwnd)) {
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+ }
+
+ // Attempt to bring the dialog window to the foreground if needed. If the
+ // window is in the background and cannot be brought forward, this call will
+ // flash the placeholder on the taskbar. Do not call SetForegroundWindow()
+ // multiple times as it will cause annoying flashing for the user.
+ It2MeConfirmationDialogWin* dialog =
+ reinterpret_cast<It2MeConfirmationDialogWin*>(ref_data);
+ if (hwnd == GetForegroundWindow()) {
+ dialog->is_foreground_window_ = true;
+ } else if (dialog->is_foreground_window_) {
+ SetForegroundWindow(hwnd);
+ dialog->is_foreground_window_ = false;
+ }
+ }
+
+ return S_OK;
+}
+
+} // namespace
+
+std::unique_ptr<It2MeConfirmationDialog>
+It2MeConfirmationDialogFactory::Create() {
+ return base::MakeUnique<It2MeConfirmationDialogWin>();
+}
+
+} // namespace remoting
« no previous file with comments | « remoting/host/it2me/it2me_confirmation_dialog_mac.cc ('k') | remoting/host/win/core.rc.jinja2 » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698