// Copyright (c) 2012 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 "stdafx.h"
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
struct Globals {
LPTHREAD_START_ROUTINE host_main;
void* host_context;
HWND core_window;
HWND host_window;
HANDLE host_thread;
DWORD main_thread_id;
} globals;
void ODS(const char* str, LONG_PTR val = 0) {
char buf[80];
size_t len = strlen(str);
if (len > 50) {
::OutputDebugStringA("ODS: buffer too long");
return;
}
if (str[0] == '!') {
// Fatal error.
DWORD gle = ::GetLastError();
if (::IsDebuggerPresent())
__debugbreak();
wsprintfA(buf, "ODS:fatal %s (%p) gle=0x%x", str, val, gle);
::MessageBoxA(NULL, buf, "!!!", MB_OK);
::ExitProcess(gle);
} else {
// Just information.
wsprintfA(buf, "ODS:%s (%p)\n", str, val);
::OutputDebugStringA(buf);
}
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
WPARAM wparam, LPARAM lparam) {
PAINTSTRUCT ps;
HDC hdc;
switch (message) {
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
ODS("Metro WM_DESTROY received");
break;
default:
return DefWindowProc(hwnd, message, wparam, lparam);
}
return 0;
}
HWND CreateMetroTopLevelWindow() {
HINSTANCE hInst = reinterpret_cast<HINSTANCE>(&__ImageBase);
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(wcex);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInst;
wcex.hIcon = 0;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_INACTIVECAPTION+1);
wcex.lpszMenuName = 0;
wcex.lpszClassName = L"Windows.UI.Core.CoreWindow";
wcex.hIconSm = 0;
HWND hwnd = ::CreateWindowExW(0,
MAKEINTATOM(::RegisterClassExW(&wcex)),
L"metro_metro",
WS_POPUP,
0, 0, 0, 0,
NULL, NULL, hInst, NULL);
return hwnd;
}
DWORD WINAPI HostThread(void*) {
// The sleeps simulates the delay we have in the actual metro code
// which takes in account the corewindow being created and some other
// unknown machinations of metro.
ODS("Chrome main thread", ::GetCurrentThreadId());
::Sleep(30);
return globals.host_main(globals.host_context);
}
extern "C" __declspec(dllexport)
int InitMetro(LPTHREAD_START_ROUTINE thread_proc, void* context) {
ODS("InitMetro [Win7 emulation]");
HWND window = CreateMetroTopLevelWindow();
if (!window)
return 1;
// This magic incatation tells windows that the window is going fullscreen
// so the taskbar gets out of the wait automatically.
::SetWindowPos(window,
HWND_TOP,
0,0,
GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN),
SWP_SHOWWINDOW);
// Ready to start our caller.
globals.core_window = window;
globals.host_main = thread_proc;
globals.host_context = context;
HANDLE thread = ::CreateThread(NULL, 0, &HostThread, NULL, 0, NULL);
// Main message loop.
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
}
extern "C" _declspec(dllexport) HWND GetRootWindow() {
ODS("GetRootWindow", ULONG_PTR(globals.core_window));
return globals.core_window;
}
extern "C" _declspec(dllexport) void SetFrameWindow(HWND window) {
ODS("SetFrameWindow", ULONG_PTR(window));
globals.host_window = window;
}
extern "C" __declspec(dllexport) const wchar_t* GetInitialUrl() {
return L"";
}