summaryrefslogtreecommitdiffstats
path: root/chrome_frame/test/net/process_singleton_subclass.cc
blob: 91a3befc673019022065863b25d43fc9590846c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// Copyright (c) 2009 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 "chrome_frame/test/net/process_singleton_subclass.h"

#include "base/command_line.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "chrome/browser/browser_process_impl.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome_frame/test/net/test_automation_provider.h"
#include "chrome_frame/function_stub.h"
#include "testing/gtest/include/gtest/gtest.h"

ProcessSingletonSubclass::ProcessSingletonSubclass(
    ProcessSingletonSubclassDelegate* delegate)
    : stub_(NULL), delegate_(delegate), original_wndproc_(NULL) {
}

ProcessSingletonSubclass::~ProcessSingletonSubclass() {
  if (stub_) {
    stub_->BypassStub(reinterpret_cast<void*>(original_wndproc_));
  }
}

bool ProcessSingletonSubclass::Subclass(const FilePath& user_data_dir) {
  DCHECK(stub_ == NULL);
  DCHECK(original_wndproc_ == NULL);
  HWND hwnd = FindWindowEx(HWND_MESSAGE, NULL, chrome::kMessageWindowClass,
                           user_data_dir.ToWStringHack().c_str());
  if (!::IsWindow(hwnd))
    return false;

  // The window must be in this process for us to be able to subclass it.
  DWORD pid = 0;
  ::GetWindowThreadProcessId(hwnd, &pid);
  EXPECT_EQ(pid, ::GetCurrentProcessId());

  original_wndproc_ = reinterpret_cast<WNDPROC>(::GetWindowLongPtr(hwnd,
      GWLP_WNDPROC));
  stub_ = FunctionStub::Create(reinterpret_cast<uintptr_t>(this),
                               &SubclassWndProc);
  DCHECK(stub_);
  ::SetWindowLongPtr(hwnd, GWLP_WNDPROC,
      reinterpret_cast<LONG_PTR>(stub_->code()));
  return true;
}

// static
LRESULT ProcessSingletonSubclass::SubclassWndProc(ProcessSingletonSubclass* me,
                                                  HWND hwnd, UINT msg,
                                                  WPARAM wp, LPARAM lp) {
  switch (msg) {
    case WM_COPYDATA:
      return me->OnCopyData(hwnd, reinterpret_cast<HWND>(wp),
                            reinterpret_cast<COPYDATASTRUCT*>(lp));
    default:
      break;
  }

  return me->original_wndproc_(hwnd, msg, wp, lp);
}

// static
LRESULT ProcessSingletonSubclass::OnCopyData(HWND hwnd, HWND from_hwnd,
                                             const COPYDATASTRUCT* cds) {
  // We should have enough room for the shortest command (min_message_size)
  // and also be a multiple of wchar_t bytes. The shortest command
  // possible is L"START\0\0" (empty current directory and command line).
  static const int kMinMessageSize = sizeof(L"START\0");
  EXPECT_TRUE(kMinMessageSize <= cds->cbData);

  if (kMinMessageSize > cds->cbData)
    return TRUE;

  // We split the string into 4 parts on NULLs.
  const wchar_t* begin = reinterpret_cast<const wchar_t*>(cds->lpData);
  const wchar_t* end = begin + (cds->cbData / sizeof(wchar_t));
  const wchar_t kNull = L'\0';
  const wchar_t* eos = wmemchr(begin, kNull, end - begin);
  EXPECT_NE(eos, end);
  if (lstrcmpW(begin, L"START") == 0) {
    begin = eos + 1;
    EXPECT_TRUE(begin <= end);
    eos = wmemchr(begin, kNull, end - begin);
    EXPECT_NE(eos, end);

    // Get current directory.
    const wchar_t* cur_dir = begin;
    begin = eos + 1;
    EXPECT_TRUE(begin <= end);
    eos = wmemchr(begin, kNull, end - begin);
    // eos might be equal to end at this point.

    // Get command line.
    std::wstring cmd_line(begin, static_cast<size_t>(end - begin));

    CommandLine parsed_command_line = CommandLine::FromString(cmd_line);
    std::string channel_id(WideToASCII(parsed_command_line.GetSwitchValue(
        switches::kAutomationClientChannelID)));
    EXPECT_FALSE(channel_id.empty());

    delegate_->OnConnectAutomationProviderToChannel(channel_id);
  }
  return TRUE;
}