Chrome Windows Debugger Extension Skeleton

This is a skeleton of a Chrome Windows Debugger extension that will
provide convenience commands for developers using ntsd, cdb, or windbg.

BUG=

Review-Url: https://codereview.chromium.org/2612193002
Cr-Original-Commit-Position: refs/heads/master@{#443414}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: fd54b5ccf9c4e391de0bcfe8e852f6784e1a9268
diff --git a/chromeexts/BUILD.gn b/chromeexts/BUILD.gn
new file mode 100644
index 0000000..1b344ea
--- /dev/null
+++ b/chromeexts/BUILD.gn
@@ -0,0 +1,10 @@
+# Copyright 2017 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.
+
+shared_library("chromeexts") {
+  sources = [
+    "chromeexts.cc",
+    "chromeexts.def",
+  ]
+}
diff --git a/chromeexts/OWNERS b/chromeexts/OWNERS
new file mode 100644
index 0000000..18583cd
--- /dev/null
+++ b/chromeexts/OWNERS
@@ -0,0 +1 @@
+robliao@chromium.org
diff --git a/chromeexts/chromeexts.cc b/chromeexts/chromeexts.cc
new file mode 100644
index 0000000..dad25b7
--- /dev/null
+++ b/chromeexts/chromeexts.cc
@@ -0,0 +1,88 @@
+// Copyright 2017 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 <dbgeng.h>
+#include <wrl/client.h>
+
+namespace {
+using Microsoft::WRL::ComPtr;
+constexpr size_t kMaxWindowStringLength = 256;
+}  // namespace
+
+HRESULT CALLBACK DebugExtensionInitialize(ULONG* version, ULONG* flags) {
+  *version = DEBUG_EXTENSION_VERSION(0, 1);
+  *flags = 0;
+  return S_OK;
+}
+
+void CALLBACK DebugExtensionUninitialize() {}
+
+HRESULT CALLBACK help(IDebugClient* client, PCSTR args) {
+  ComPtr<IDebugControl> debug_control;
+  HRESULT hr = client->QueryInterface(IID_PPV_ARGS(&debug_control));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  debug_control->Output(DEBUG_OUTPUT_NORMAL,
+                        "Chrome Windows Debugger Extension\n");
+  debug_control->Output(DEBUG_OUTPUT_NORMAL,
+                        "hwnd - Displays basic hwnd info.\n");
+  return S_OK;
+}
+
+HRESULT CALLBACK hwnd(IDebugClient* client, PCSTR args) {
+  ComPtr<IDebugControl> debug_control;
+  HRESULT hr = client->QueryInterface(IID_PPV_ARGS(&debug_control));
+  if (FAILED(hr)) {
+    return hr;
+  }
+
+  // While sizeof(HWND) can change between 32-bit and 64-bit platforms, Windows
+  // only cares about the lower 32-bits. We evaluate as 64-bit as a convenience
+  // and truncate the displayed hwnds to 32-bit below.
+  // See https://msdn.microsoft.com/en-us/library/aa384203.aspx
+  DEBUG_VALUE value;
+  hr = debug_control->Evaluate(args, DEBUG_VALUE_INT64, &value, nullptr);
+  if (FAILED(hr)) {
+    debug_control->Output(DEBUG_OUTPUT_ERROR, "Unable to evaluate %s\n", args);
+    return hr;
+  }
+
+  HWND hwnd = reinterpret_cast<HWND>(value.I64);
+  if (!IsWindow(hwnd)) {
+    debug_control->Output(DEBUG_OUTPUT_NORMAL, "Not a window: %s\n", args);
+    return E_FAIL;
+  }
+
+  wchar_t title[kMaxWindowStringLength];
+  GetWindowText(hwnd, title, ARRAYSIZE(title));
+  debug_control->Output(DEBUG_OUTPUT_NORMAL, "Title: %ws\n", title);
+  wchar_t window_class[kMaxWindowStringLength];
+  GetClassName(hwnd, window_class, ARRAYSIZE(window_class));
+  debug_control->Output(DEBUG_OUTPUT_NORMAL, "Class: %ws\n", window_class);
+  debug_control->Output(DEBUG_OUTPUT_NORMAL, "Hierarchy: \n");
+  debug_control->Output(DEBUG_OUTPUT_NORMAL, "   Owner: %08x Parent: %08x\n",
+                        GetWindow(hwnd, GW_OWNER), GetParent(hwnd));
+  debug_control->Output(DEBUG_OUTPUT_NORMAL, "   Prev:  %08x Next:   %08x\n",
+                        GetNextWindow(hwnd, GW_HWNDPREV),
+                        GetNextWindow(hwnd, GW_HWNDNEXT));
+  debug_control->Output(DEBUG_OUTPUT_NORMAL, "Styles: %08x (Ex: %08x)\n",
+                        GetWindowLong(hwnd, GWL_STYLE),
+                        GetWindowLong(hwnd, GWL_EXSTYLE));
+  RECT window_rect;
+  if (GetWindowRect(hwnd, &window_rect)) {
+    debug_control->Output(DEBUG_OUTPUT_NORMAL, "Bounds: (%d, %d) %dx%d\n",
+                          window_rect.left, window_rect.top,
+                          window_rect.right - window_rect.left,
+                          window_rect.bottom - window_rect.top);
+  } else {
+    DWORD last_error = GetLastError();
+    debug_control->Output(DEBUG_OUTPUT_NORMAL,
+                          "Bounds: Unavailable (Last Error = %d)\n",
+                          last_error);
+  }
+  return S_OK;
+}
diff --git a/chromeexts/chromeexts.def b/chromeexts/chromeexts.def
new file mode 100644
index 0000000..642d119
--- /dev/null
+++ b/chromeexts/chromeexts.def
@@ -0,0 +1,12 @@
+; Copyright 2017 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.
+
+LIBRARY "chromeexts.dll"
+
+EXPORTS
+  DebugExtensionInitialize
+  DebugExtensionUninitialize
+  help
+  hwnd
+