Index: chrome_frame/test/net/process_singleton_subclass.cc |
=================================================================== |
--- chrome_frame/test/net/process_singleton_subclass.cc (revision 0) |
+++ chrome_frame/test/net/process_singleton_subclass.cc (revision 0) |
@@ -0,0 +1,111 @@ |
+// 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(L""); |
+ parsed_command_line.ParseFromString(cmd_line); |
+ std::string channel_id(WideToASCII(parsed_command_line.GetSwitchValue( |
+ switches::kAutomationClientChannelID))); |
+ EXPECT_FALSE(channel_id.empty()); |
+ |
+ delegate_->OnConnectAutomationProviderToChannel(channel_id); |
+ } |
+ return TRUE; |
+} |