Coding style (settings) (#1012)

This commit is contained in:
Enrico Giordani
2019-12-26 17:25:56 +01:00
committed by GitHub
parent 47bcb117b4
commit 9708961654
3 changed files with 385 additions and 323 deletions

View File

@@ -1,8 +1,8 @@
#include "pch.h"
#include "StreamUriResolverFromFile.h"
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::Streams::IInputStream> StreamUriResolverFromFile::UriToStreamAsync(const winrt::Windows::Foundation::Uri & uri) const {
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::Streams::IInputStream> StreamUriResolverFromFile::UriToStreamAsync(const winrt::Windows::Foundation::Uri& uri) const
{
winrt::Windows::Storage::StorageFolder folder = winrt::Windows::Storage::StorageFolder::GetFolderFromPathAsync(winrt::param::hstring(base_path)).get();
std::wstring myuri = uri.Path().c_str();
@@ -11,10 +11,12 @@ winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::Streams::II
std::replace(myuri.begin(), myuri.end(), '/', '\\');
winrt::Windows::Storage::StorageFile file = nullptr;
try {
try
{
file = folder.GetFileAsync(winrt::param::hstring(myuri)).get();
}
catch (winrt::hresult_error const& e) {
catch (winrt::hresult_error const& e)
{
WCHAR message[1024] = L"";
StringCchPrintf(message, ARRAYSIZE(message), L"failed: %ls", e.message().c_str());
MessageBox(NULL, message, L"Error", MB_OK);

View File

@@ -1,8 +1,8 @@
#pragma once
#include "pch.h"
struct StreamUriResolverFromFile : winrt::implements <StreamUriResolverFromFile, winrt::Windows::Web::IUriToStreamResolver> {
struct StreamUriResolverFromFile : winrt::implements<StreamUriResolverFromFile, winrt::Windows::Web::IUriToStreamResolver>
{
WCHAR base_path[MAX_PATH];
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::Streams::IInputStream> UriToStreamAsync(const winrt::Windows::Foundation::Uri& uri) const;
};

View File

@@ -57,7 +57,8 @@ bool g_waiting_for_close_confirmation = false;
bool g_start_in_dark_mode = false;
#ifdef _DEBUG
void NavigateToLocalhostReactServer() {
void NavigateToLocalhostReactServer()
{
// Useful for connecting to instance running in react development server.
g_webview.Navigate(Uri(hstring(L"http://localhost:8080")));
}
@@ -65,7 +66,8 @@ void NavigateToLocalhostReactServer() {
#define URI_CONTENT_ID L"\\settings-html"
void NavigateToUri(_In_ LPCWSTR uri_as_string) {
void NavigateToUri(_In_ LPCWSTR uri_as_string)
{
// initialize the base_path for the html content relative to the executable.
WINRT_VERIFY(GetModuleFileName(nullptr, local_uri_resolver.base_path, MAX_PATH));
WINRT_VERIFY(PathRemoveFileSpec(local_uri_resolver.base_path));
@@ -74,12 +76,12 @@ void NavigateToUri(_In_ LPCWSTR uri_as_string) {
g_webview.NavigateToLocalStreamUri(url, local_uri_resolver);
}
Rect client_rect_to_bounds_rect(_In_ HWND hwnd) {
Rect client_rect_to_bounds_rect(_In_ HWND hwnd)
{
RECT client_rect = { 0 };
WINRT_VERIFY(GetClientRect(hwnd, &client_rect));
Rect bounds =
{
Rect bounds = {
0,
0,
static_cast<float>(client_rect.right - client_rect.left),
@@ -89,17 +91,19 @@ Rect client_rect_to_bounds_rect(_In_ HWND hwnd) {
return bounds;
}
void resize_web_view() {
void resize_web_view()
{
Rect bounds = client_rect_to_bounds_rect(g_main_wnd);
IWebViewControlSite webViewControlSite = (IWebViewControlSite)g_webview;
webViewControlSite.Bounds(bounds);
}
#define SEND_TO_WEBVIEW_MSG 1
void send_message_to_webview(const std::wstring& msg) {
if (g_main_wnd != nullptr && wm_data_for_webview != 0) {
void send_message_to_webview(const std::wstring& msg)
{
if (g_main_wnd != nullptr && wm_data_for_webview != 0)
{
// Allocate the COPYDATASTRUCT and message to pass to the Webview.
// This is needed in order to use PostMessage, since COM calls to
// g_webview.InvokeScriptAsync can't be made from other threads.
@@ -118,10 +122,14 @@ void send_message_to_webview(const std::wstring& msg) {
}
}
void send_message_to_powertoys_runner(const std::wstring& msg) {
if (g_message_pipe != nullptr) {
void send_message_to_powertoys_runner(const std::wstring& msg)
{
if (g_message_pipe != nullptr)
{
g_message_pipe->send(msg);
} else {
}
else
{
// For Debug purposes, in case the webview is being run alone.
#ifdef _DEBUG
MessageBox(g_main_wnd, msg.c_str(), L"From Webview", MB_OK);
@@ -190,28 +198,38 @@ void send_message_to_powertoys_runner(const std::wstring& msg) {
}
}
void receive_message_from_webview(const std::wstring& msg) {
if (msg[0] == '{') {
void receive_message_from_webview(const std::wstring& msg)
{
if (msg[0] == '{')
{
// It's a JSON string, send the message to the PowerToys runner.
std::thread(send_message_to_powertoys_runner, msg).detach();
} else {
}
else
{
// It's not a JSON string, check for expected control messages.
if (msg == L"exit") {
if (msg == L"exit")
{
// WebView confirms the settings application can exit.
WINRT_VERIFY(PostMessage(g_main_wnd, wm_destroy_window, 0, 0));
} else if (msg == L"cancel-exit") {
}
else if (msg == L"cancel-exit")
{
// WebView canceled the exit request.
g_waiting_for_close_confirmation = false;
}
}
}
void initialize_webview(int nShowCmd) {
try {
void initialize_webview(int nShowCmd)
{
try
{
g_webview_process = WebViewControlProcess();
auto asyncwebview = g_webview_process.CreateWebViewControlAsync((int64_t)g_main_wnd, client_rect_to_bounds_rect(g_main_wnd));
asyncwebview.Completed([=](IAsyncOperation<WebViewControl> const& sender, AsyncStatus status) {
if (status == AsyncStatus::Completed) {
if (status == AsyncStatus::Completed)
{
WINRT_VERIFY(sender != nullptr);
g_webview = sender.GetResults();
WINRT_VERIFY(g_webview != nullptr);
@@ -236,7 +254,8 @@ void initialize_webview(int nShowCmd) {
receive_message_from_webview(message_sent);
});
g_webview.AcceleratorKeyPressed([&](IWebViewControl sender, WebViewControlAcceleratorKeyPressedEventArgs const& args) {
if (args.VirtualKey() == winrt::Windows::System::VirtualKey::F4) {
if (args.VirtualKey() == winrt::Windows::System::VirtualKey::F4)
{
// WebView swallows key-events. Detect Alt-F4 one and close the window manually.
const auto _ = g_webview.InvokeScriptAsync(hstring(L"exit_settings_app"), {});
}
@@ -249,35 +268,51 @@ void initialize_webview(int nShowCmd) {
// Navigates to settings-html/index.html or index-dark.html
NavigateToUri(g_start_in_dark_mode ? L"index-dark.html" : L"index.html");
#endif
} else if (status == AsyncStatus::Error) {
}
else if (status == AsyncStatus::Error)
{
MessageBox(NULL, L"Failed to create the WebView control.\nPlease report the bug to https://github.com/microsoft/PowerToys/issues", L"PowerToys Settings Error", MB_OK);
exit(1);
} else if (status == AsyncStatus::Started) {
}
else if (status == AsyncStatus::Started)
{
// Ignore.
} else if (status == AsyncStatus::Canceled) {
}
else if (status == AsyncStatus::Canceled)
{
// Ignore.
}
});
} catch (hresult_error const& e) {
}
catch (hresult_error const& e)
{
WCHAR message[1024] = L"";
StringCchPrintf(message, ARRAYSIZE(message), L"failed: %ls", e.message().c_str());
MessageBox(g_main_wnd, message, L"Error", MB_OK);
}
}
LRESULT CALLBACK wnd_proc_static(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch (message) {
LRESULT CALLBACK wnd_proc_static(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CLOSE:
if (g_waiting_for_close_confirmation) {
if (g_waiting_for_close_confirmation)
{
// If another WM_CLOSE is received while waiting for webview confirmation,
// allow DefWindowProc to be called and destroy the window.
break;
} else {
}
else
{
// Allow user to confirm exit in the WebView in case there's possible data loss.
g_waiting_for_close_confirmation = true;
if (g_webview != nullptr) {
if (g_webview != nullptr)
{
const auto _ = g_webview.InvokeScriptAsync(hstring(L"exit_settings_app"), {});
} else {
}
else
{
break;
}
return 0;
@@ -286,7 +321,8 @@ LRESULT CALLBACK wnd_proc_static(HWND hWnd, UINT message, WPARAM wParam, LPARAM
PostQuitMessage(0);
break;
case WM_SIZE:
if (g_webview != nullptr) {
if (g_webview != nullptr)
{
resize_web_view();
}
break;
@@ -294,8 +330,7 @@ LRESULT CALLBACK wnd_proc_static(HWND hWnd, UINT message, WPARAM wParam, LPARAM
wm_data_for_webview = RegisterWindowMessageW(L"PTSettingsCopyDataWebView");
wm_destroy_window = RegisterWindowMessageW(L"PTSettingsParentTerminated");
break;
case WM_DPICHANGED:
{
case WM_DPICHANGED: {
// Resize the window using the suggested rect
RECT* const prcNewWindow = (RECT*)lParam;
SetWindowPos(hWnd,
@@ -307,35 +342,42 @@ LRESULT CALLBACK wnd_proc_static(HWND hWnd, UINT message, WPARAM wParam, LPARAM
SWP_NOZORDER | SWP_NOACTIVATE);
}
break;
case WM_NCCREATE:
{
case WM_NCCREATE: {
// Enable auto-resizing the title bar
EnableNonClientDpiScaling(hWnd);
}
break;
default:
if (message == wm_data_for_webview) {
if (message == wm_data_for_webview)
{
PCOPYDATASTRUCT msg = (PCOPYDATASTRUCT)lParam;
if (msg->dwData == SEND_TO_WEBVIEW_MSG) {
if (msg->dwData == SEND_TO_WEBVIEW_MSG)
{
wchar_t* json_message = (wchar_t*)(msg->lpData);
if (g_webview != nullptr) {
if (g_webview != nullptr)
{
const auto _ = g_webview.InvokeScriptAsync(hstring(L"receive_from_settings_app"), { hstring(json_message) });
}
delete[] json_message;
}
// wnd_proc_static is responsible for freeing memory.
delete msg;
} else {
if (message == wm_destroy_window) {
}
else
{
if (message == wm_destroy_window)
{
DestroyWindow(hWnd);
}
}
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);;
return DefWindowProc(hWnd, message, wParam, lParam);
;
}
void register_classes(HINSTANCE hInstance) {
void register_classes(HINSTANCE hInstance)
{
WNDCLASSEXW wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
@@ -354,7 +396,8 @@ void register_classes(HINSTANCE hInstance) {
WINRT_VERIFY(RegisterClassExW(&wcex));
}
HWND create_main_window(HINSTANCE hInstance) {
HWND create_main_window(HINSTANCE hInstance)
{
RECT desktopRect;
const HWND hDesktop = GetDesktopWindow();
WINRT_VERIFY(hDesktop != nullptr);
@@ -378,29 +421,37 @@ HWND create_main_window(HINSTANCE hInstance) {
nullptr);
}
void wait_on_parent_process_thread(DWORD pid) {
void wait_on_parent_process_thread(DWORD pid)
{
HANDLE process = OpenProcess(SYNCHRONIZE, FALSE, pid);
if (process != nullptr) {
if (WaitForSingleObject(process, INFINITE) == WAIT_OBJECT_0) {
if (process != nullptr)
{
if (WaitForSingleObject(process, INFINITE) == WAIT_OBJECT_0)
{
// If it's possible to detect when the PowerToys process terminates, message the main window.
CloseHandle(process);
if (g_main_wnd) {
if (g_main_wnd)
{
WINRT_VERIFY(PostMessage(g_main_wnd, wm_destroy_window, 0, 0));
}
} else {
}
else
{
CloseHandle(process);
}
}
}
void quit_when_parent_terminates(std::wstring parent_pid) {
void quit_when_parent_terminates(std::wstring parent_pid)
{
DWORD pid = std::stol(parent_pid);
std::thread(wait_on_parent_process_thread, pid).detach();
}
// Parse arguments: initialize two-way IPC message pipe and if settings window is to be started
// in dark mode.
void parse_args() {
void parse_args()
{
// Expected calling arguments:
// [0] - This executable's path.
// [1] - PowerToys pipe server.
@@ -411,27 +462,34 @@ void parse_args() {
int n_args;
argument_list = CommandLineToArgvW(GetCommandLineW(), &n_args);
if (n_args > 3) {
if (n_args > 3)
{
g_message_pipe = new TwoWayPipeMessageIPC(std::wstring(argument_list[2]), std::wstring(argument_list[1]), send_message_to_webview);
g_message_pipe->start(nullptr);
quit_when_parent_terminates(std::wstring(argument_list[3]));
} else {
}
else
{
#ifndef _DEBUG
MessageBox(nullptr, L"This executable isn't supposed to be called as a stand-alone process", L"Error running settings", MB_OK);
exit(1);
#endif
}
if (n_args > 4) {
if (n_args > 4)
{
g_start_in_dark_mode = wcscmp(argument_list[4], L"dark") == 0;
}
LocalFree(argument_list);
}
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd) {
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{
CoInitialize(nullptr);
if (is_process_elevated()) {
if (!drop_elevated_privileges()) {
if (is_process_elevated())
{
if (!drop_elevated_privileges())
{
MessageBox(NULL, L"Failed to drop admin privileges.\nPlease report the bug to https://github.com/microsoft/PowerToys/issues", L"PowerToys Settings Error", MB_OK);
exit(1);
}
@@ -441,7 +499,8 @@ int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _
parse_args();
register_classes(hInstance);
g_main_wnd = create_main_window(hInstance);
if (g_main_wnd == nullptr) {
if (g_main_wnd == nullptr)
{
MessageBox(NULL, L"Failed to create main window.\nPlease report the bug to https://github.com/microsoft/PowerToys/issues", L"PowerToys Settings Error", MB_OK);
exit(1);
}
@@ -449,7 +508,8 @@ int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _
// Main message loop.
MSG msg;
while (GetMessage(&msg, nullptr, 0, 0)) {
while (GetMessage(&msg, nullptr, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}