15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h> 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/hang_monitor/hung_plugin_action.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/version.h" 11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "chrome/browser/ui/simple_message_box.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/logging_chrome.h" 13ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "content/public/browser/plugin_service.h" 14ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "content/public/common/webplugininfo.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "grit/generated_resources.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h" 17d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/win/hwnd_util.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kGTalkPluginName[] = L"Google Talk Plugin"; 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kGTalkPluginLogMinVersion = 26; // For version 2.6 and below. 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum GTalkPluginLogVersion { 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTALK_PLUGIN_VERSION_MIN = 0, 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTALK_PLUGIN_VERSION_27, 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTALK_PLUGIN_VERSION_28, 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTALK_PLUGIN_VERSION_29, 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTALK_PLUGIN_VERSION_30, 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTALK_PLUGIN_VERSION_31, 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTALK_PLUGIN_VERSION_32, 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTALK_PLUGIN_VERSION_33, 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTALK_PLUGIN_VERSION_34, 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTALK_PLUGIN_VERSION_MAX 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Converts the version string of Google Talk Plugin to a version enum. The 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// version format is "major(1 digit).minor(1 digit).sub(1 or 2 digits)", 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for example, "2.7.10" and "2.8.1". Converts the string to a number as 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 10 * major + minor - kGTalkPluginLogMinVersion. 41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)GTalkPluginLogVersion GetGTalkPluginVersion(const base::string16& version) { 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int gtalk_plugin_version = GTALK_PLUGIN_VERSION_MIN; 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Version plugin_version; 44ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch content::WebPluginInfo::CreateVersionFromString(version, &plugin_version); 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (plugin_version.IsValid() && plugin_version.components().size() >= 2) { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gtalk_plugin_version = 10 * plugin_version.components()[0] + 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) plugin_version.components()[1] - kGTalkPluginLogMinVersion; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (gtalk_plugin_version < GTALK_PLUGIN_VERSION_MIN) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GTALK_PLUGIN_VERSION_MIN; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (gtalk_plugin_version > GTALK_PLUGIN_VERSION_MAX) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GTALK_PLUGIN_VERSION_MAX; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return static_cast<GTalkPluginLogVersion>(gtalk_plugin_version); 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HungPluginAction::HungPluginAction() : current_hung_plugin_window_(NULL) { 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HungPluginAction::~HungPluginAction() { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HungPluginAction::OnHungWindowDetected(HWND hung_window, 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HWND top_level_window, 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ActionOnHungWindow* action) { 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (NULL == action) { 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!IsWindow(hung_window)) { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool continue_hang_detection = true; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD hung_window_process_id = 0; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD top_level_window_process_id = 0; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetWindowThreadProcessId(hung_window, &hung_window_process_id); 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetWindowThreadProcessId(top_level_window, &top_level_window_process_id); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *action = HungWindowNotification::HUNG_WINDOW_IGNORE; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (top_level_window_process_id != hung_window_process_id) { 84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 plugin_name; 85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 plugin_version; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetPluginNameAndVersion(hung_window, 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) top_level_window_process_id, 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &plugin_name, 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &plugin_version); 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (plugin_name.empty()) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) plugin_name = l10n_util::GetStringUTF16(IDS_UNKNOWN_PLUGIN_NAME); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (kGTalkPluginName == plugin_name) { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UMA_HISTOGRAM_ENUMERATION("GTalkPlugin.Hung", 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetGTalkPluginVersion(plugin_version), 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GTALK_PLUGIN_VERSION_MAX + 1); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (logging::DialogsAreSuppressed()) { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED() << "Terminated a hung plugin process."; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *action = HungWindowNotification::HUNG_WINDOW_TERMINATE_PROCESS; 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16 title = l10n_util::GetStringUTF16( 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDS_BROWSER_HANGMONITOR_TITLE); 104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const base::string16 message = l10n_util::GetStringFUTF16( 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) IDS_BROWSER_HANGMONITOR, plugin_name); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Before displaying the message box, invoke SendMessageCallback on the 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // hung window. If the callback ever hits, the window is not hung anymore 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and we can dismiss the message box. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SendMessageCallback(hung_window, 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WM_NULL, 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HungWindowResponseCallback, 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<ULONG_PTR>(this)); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_hung_plugin_window_ = hung_window; 116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) if (chrome::ShowMessageBox( 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NULL, title, message, chrome::MESSAGE_BOX_TYPE_QUESTION) == 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chrome::MESSAGE_BOX_RESULT_YES) { 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *action = HungWindowNotification::HUNG_WINDOW_TERMINATE_PROCESS; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the user choses to ignore the hung window warning, the 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // message timeout for this window should be doubled. We only 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // double the timeout property on the window if the property 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // exists. The property is deleted if the window becomes 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // responsive. 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue_hang_detection = false; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(disable:4311) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int child_window_message_timeout = 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<int>(GetProp( 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) hung_window, HungWindowDetector::kHungChildWindowTimeout)); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(default:4311) 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (child_window_message_timeout) { 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) child_window_message_timeout *= 2; 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(disable:4312) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetProp(hung_window, HungWindowDetector::kHungChildWindowTimeout, 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<HANDLE>(child_window_message_timeout)); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma warning(default:4312) 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_hung_plugin_window_ = NULL; 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HungWindowNotification::HUNG_WINDOW_TERMINATE_PROCESS == *action) { 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Enable the top-level window just in case the plugin had been 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // displaying a modal box that had disabled the top-level window 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnableWindow(top_level_window, TRUE); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return continue_hang_detection; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void HungPluginAction::OnWindowResponsive(HWND window) { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (window == current_hung_plugin_window_) { 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The message timeout for this window should fallback to the default 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // timeout as this window is now responsive. 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RemoveProp(window, HungWindowDetector::kHungChildWindowTimeout); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The monitored plugin recovered. Let's dismiss the message box. 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EnumThreadWindows(GetCurrentThreadId(), 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<WNDENUMPROC>(DismissMessageBox), 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NULL); 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool HungPluginAction::GetPluginNameAndVersion(HWND plugin_window, 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD browser_process_id, 165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16* plugin_name, 166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16* plugin_version) { 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(plugin_name); 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(plugin_version); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HWND window_to_check = plugin_window; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (NULL != window_to_check) { 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD process_id = 0; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetWindowThreadProcessId(window_to_check, &process_id); 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (process_id == browser_process_id) { 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we have reached a window the that belongs to the browser process 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we have gone too far. 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 178ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch if (content::PluginService::GetInstance()->GetPluginInfoFromWindow( 179ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch window_to_check, plugin_name, plugin_version)) { 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) window_to_check = GetParent(window_to_check); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BOOL CALLBACK HungPluginAction::DismissMessageBox(HWND window, LPARAM ignore) { 189a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) base::string16 class_name = gfx::GetClassName(window); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // #32770 is the dialog window class which is the window class of 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the message box being displayed. 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (class_name == L"#32770") { 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EndDialog(window, IDNO); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return FALSE; 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return TRUE; 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void CALLBACK HungPluginAction::HungWindowResponseCallback(HWND target_window, 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UINT message, 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ULONG_PTR data, 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LRESULT result) { 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HungPluginAction* instance = reinterpret_cast<HungPluginAction*>(data); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(NULL != instance); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (NULL != instance) { 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) instance->OnWindowResponsive(target_window); 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 210