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
#include <flutter/dart_project.h>
#include <flutter/flutter_view_controller.h>
#include <flutter_windows.h>
#include <windows.h>
#include <functional>
#include <string>
#include <vector>
#include "flutter_window.h"
#include "utils.h"
namespace {
// The copy of the app this process is: one per data folder, so a second
// launch shows the running window instead of opening another.
std::wstring InstanceKey(const std::vector<std::string>& args) {
std::string data_dir;
for (const auto& arg : args) {
if (arg.rfind("--data-dir=", 0) == 0) {
data_dir = arg.substr(11);
}
}
return std::to_wstring(std::hash<std::string>{}(data_dir) & 0x7fffffff);
}
bool HasArgument(const std::vector<std::string>& args, const char* name) {
for (const auto& arg : args) {
if (arg == name) {
return true;
}
}
return false;
}
// The window's origin, in logical pixels, that centers [size] in the
// primary monitor's work area.
Win32Window::Point CenteredOrigin(const Win32Window::Size& size) {
RECT work;
SystemParametersInfoW(SPI_GETWORKAREA, 0, &work, 0);
HMONITOR monitor = MonitorFromPoint(POINT{0, 0}, MONITOR_DEFAULTTOPRIMARY);
double scale = FlutterDesktopGetDpiForMonitor(monitor) / 96.0;
double width = (work.right - work.left) / scale;
double height = (work.bottom - work.top) / scale;
double x = work.left / scale + (width - size.width) / 2;
double y = work.top / scale + (height - size.height) / 2;
return Win32Window::Point(static_cast<unsigned int>(x > 0 ? x : 0),
static_cast<unsigned int>(y > 0 ? y : 0));
}
} // namespace
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
_In_ wchar_t *command_line, _In_ int show_command) {
// Attach to console when present (e.g., 'flutter run') or create a
// new console when running with a debugger.
if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
CreateAndAttachConsole();
}
// Initialize COM, so that it is available for use in the library and/or
// plugins.
::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
flutter::DartProject project(L"data");
std::vector<std::string> command_line_arguments =
GetCommandLineArguments();
const std::wstring key = InstanceKey(command_line_arguments);
HANDLE instance_mutex =
::CreateMutexW(nullptr, TRUE, (L"Local\\VPNClient-" + key).c_str());
if (::GetLastError() == ERROR_ALREADY_EXISTS) {
// Ask the running copy to show its window, and let it take the focus.
::AllowSetForegroundWindow(ASFW_ANY);
::PostMessageW(HWND_BROADCAST, ::RegisterWindowMessageW(L"VPNClient.Activate"),
static_cast<WPARAM>(std::stoul(key)), 0);
if (instance_mutex) {
::CloseHandle(instance_mutex);
}
::CoUninitialize();
return EXIT_SUCCESS;
}
// Started by Windows at sign-in, or by an update of a copy that was in
// the tray: stay in the tray.
const bool start_hidden = HasArgument(command_line_arguments, "--autostart") ||
HasArgument(command_line_arguments, "--hidden");
project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
FlutterWindow window(project, static_cast<WPARAM>(std::stoul(key)), start_hidden);
Win32Window::Size size(820, 680);
Win32Window::Point origin = CenteredOrigin(size);
if (!window.Create(L"FoxyVPN", origin, size)) {
return EXIT_FAILURE;
}
window.SetQuitOnClose(true);
::MSG msg;
while (::GetMessage(&msg, nullptr, 0, 0)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
if (instance_mutex) {
::CloseHandle(instance_mutex);
}
::CoUninitialize();
return EXIT_SUCCESS;
}