diff --git a/LGTV Companion Service/LGTV Companion Service.vcxproj b/LGTV Companion Service/LGTV Companion Service.vcxproj index 26b026e..7eedf4a 100644 --- a/LGTV Companion Service/LGTV Companion Service.vcxproj +++ b/LGTV Companion Service/LGTV Companion Service.vcxproj @@ -119,6 +119,7 @@ _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true C:\Users\jorge\Programs\boost_1_75_0;%(AdditionalIncludeDirectories) + MultiThreadedDebug Console diff --git a/LGTV Companion Service/Service.cpp b/LGTV Companion Service/Service.cpp index 6313e0b..09f6941 100644 --- a/LGTV Companion Service/Service.cpp +++ b/LGTV Companion Service/Service.cpp @@ -800,6 +800,7 @@ void InitDeviceSessions() params.PowerOnTimeout = Prefs.PowerOnTimeout; CSession S(¶ms); + S.DeviceID = params.DeviceId; DeviceCtrlSessions.push_back(S); Log(s.str()); } @@ -981,7 +982,6 @@ void IPCThread(void) SetSecurityDescriptorDacl(psd, TRUE, (PACL)NULL, FALSE); SECURITY_ATTRIBUTES sa = { sizeof(sa), psd, FALSE }; - // Log("Creating named pipe"); hPipe = CreateNamedPipe(PIPENAME, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists... @@ -1002,7 +1002,7 @@ void IPCThread(void) transform(t.begin(), t.end(), t.begin(), ::tolower); vector cmd = stringsplit(t, " "); - if (cmd.size() > 1) + if (cmd.size() > 0) { int param1 = 0; @@ -1030,6 +1030,16 @@ void IPCThread(void) param1 = APP_CMDLINE_SETHDMI3; else if (param == "-sethdmi4") param1 = APP_CMDLINE_SETHDMI4; + else if (param == "-clearlog") + { + string w = "IPC, clear log "; + wstring log = DataPath; + log += L"Log.txt"; + w += narrow(log); + Log(w); + DeleteFile(log.c_str()); + } + else if (param1 > 0) { if (param1 == APP_IPC_DAEMON) @@ -1099,7 +1109,47 @@ void IPCThread(void) Log("IPC, Remote session disconnected."); } } + else if (param == "topology") + { + param1 = APP_IPC_DAEMON_TOPOLOGY; + for (auto &d : DeviceCtrlSessions) + { + d.SetTopology(false); + } + } + + } + else if (param1 == APP_IPC_DAEMON_TOPOLOGY) + { + if (param == "*") + { + //debuggy + stringstream s; + s << "IPC, windows monitor topology was changed."; + Log(s.str()); + DispatchSystemPowerEvent(SYSTEM_EVENT_TOPOLOGY); + } + else + { + for (auto &d : DeviceCtrlSessions) + { + string id = d.DeviceID; + transform(id.begin(), id.end(), id.begin(), ::tolower); + + if (param == id) + { + //debuggy + stringstream s; + s << "IPC, "; + s << d.DeviceID; + s << " - enabled in windows monitor topology."; + Log(s.str()); + d.SetTopology(true); + } + } + } } + else { for (auto& device : DeviceCtrlSessions) @@ -1264,4 +1314,4 @@ vector GetOwnIP(void) } } return IPs; -} \ No newline at end of file +} diff --git a/LGTV Companion Service/Service.h b/LGTV Companion Service/Service.h index ad9f6bf..9403cde 100644 --- a/LGTV Companion Service/Service.h +++ b/LGTV Companion Service/Service.h @@ -37,7 +37,7 @@ #pragma comment(lib, "Iphlpapi.lib") #define APPNAME L"LGTV Companion" -#define APPVERSION L"1.7.0" +#define APPVERSION L"1.8.0" #define SVCNAME L"LGTVsvc" #define SVCDISPLAYNAME L"LGTV Companion Service" #define SERVICE_PORT "3000" @@ -53,6 +53,7 @@ #define JSON_IDLEBLANK "BlankWhenIdle" #define JSON_IDLEBLANKDELAY "BlankWhenIdleDelay" #define JSON_RDP_POWEROFF "PowerOffDuringRDP" +#define JSON_ADHERETOPOLOGY "AdhereDisplayTopology" #define SERVICE_DEPENDENCIES L"Dhcp\0Dnscache\0LanmanServer\0\0" #define SERVICE_ACCOUNT NULL //L"NT AUTHORITY\\LocalService" @@ -77,6 +78,7 @@ #define SYSTEM_EVENT_FORCESETHDMI 15 #define SYSTEM_EVENT_BOOT 16 #define SYSTEM_EVENT_UNBLANK 17 +#define SYSTEM_EVENT_TOPOLOGY 18 #define APP_CMDLINE_ON 1 #define APP_CMDLINE_OFF 2 @@ -89,6 +91,9 @@ #define APP_CMDLINE_SETHDMI2 9 #define APP_CMDLINE_SETHDMI3 10 #define APP_CMDLINE_SETHDMI4 11 +#define APP_IPC_DAEMON_TOPOLOGY 12 + + #define WOL_NETWORKBROADCAST 1 #define WOL_IPSEND 2 @@ -146,11 +151,15 @@ class CSession { void SystemEvent(DWORD, int param = 0); SESSIONPARAMETERS GetParams(); bool IsBusy(); + void SetTopology(bool); + std::string DeviceID; private: time_t ScreenDimmedRequestTime = 0; bool ThreadedOpDisplayOn = false; bool ThreadedOpDisplayOff = false; bool ThreadedOpDisplaySetHdmiInput = false; + bool AdhereTopology = false; + bool TopologyEnabled = false; time_t ThreadedOpDisplayOffTime = 0; void TurnOnDisplay(bool SendWOL); void TurnOffDisplay(bool forced, bool dimmed, bool blankscreen); @@ -183,4 +192,4 @@ void SetDisplayHdmiInputThread(SESSIONPARAMETERS*, bool*, int, int); void IPCThread(void); void WOLthread(SESSIONPARAMETERS*, bool*, int); std::vector stringsplit(std::string str, std::string token); -std::vector GetOwnIP(void); +std::vector GetOwnIP(void); \ No newline at end of file diff --git a/LGTV Companion Service/Session.cpp b/LGTV Companion Service/Session.cpp index 807beee..941f224 100644 --- a/LGTV Companion Service/Session.cpp +++ b/LGTV Companion Service/Session.cpp @@ -23,10 +23,7 @@ namespace { MIB_IPNET_ROW2 row; row.InterfaceLuid = luid; row.Address = address; - - std::stringstream log; - log << "DeleteIpNetEntry2() = " << DeleteIpNetEntry2(&row); - Log(log.str()); + DeleteIpNetEntry2(&row); } private: @@ -43,7 +40,6 @@ namespace { log << "GetBestRoute2()"; if (result != NO_ERROR) { - std::stringstream log; log << " failed with code " << result; Log(log.str()); return boost::none; @@ -72,9 +68,9 @@ namespace { row.PhysicalAddressLength = sizeof(macAddress); const auto result = CreateIpNetEntry2(&row); - std::stringstream log; - log << "CreateIpNetEntry2() = " << result; - Log(log.str()); +// std::stringstream log; +// log << "CreateIpNetEntry2() = " << result; +// Log(log.str()); if (result != NO_ERROR) return nullptr; return std::make_unique(*luid, destination); @@ -124,6 +120,16 @@ bool CSession::IsBusy(void) mMutex.unlock(); return ret; } +void CSession::SetTopology(bool bEnabled) +{ + //thread safe section + while (!mMutex.try_lock()) + Sleep(MUTEX_WAIT); + TopologyEnabled = bEnabled; + AdhereTopology = true; + mMutex.unlock(); + return; +} void CSession::SetDisplayHdmiInput(int HdmiInput) { string s; @@ -262,12 +268,26 @@ void CSession::SystemEvent(DWORD dwMsg, int param) case SYSTEM_EVENT_RESUMEAUTO: { if (Parameters.SetHDMIInputOnResume) - SetDisplayHdmiInput(Parameters.SetHDMIInputOnResumeToNumber); + { + if (AdhereTopology) + { + if (TopologyEnabled) + SetDisplayHdmiInput(Parameters.SetHDMIInputOnResumeToNumber); + } + else + SetDisplayHdmiInput(Parameters.SetHDMIInputOnResumeToNumber); + } }break; case SYSTEM_EVENT_DISPLAYON: { - TurnOnDisplay(true); + if (AdhereTopology) + { + if (TopologyEnabled) + TurnOnDisplay(true); + } + else + TurnOnDisplay(true); }break; case SYSTEM_EVENT_DISPLAYOFF: { @@ -280,22 +300,56 @@ void CSession::SystemEvent(DWORD dwMsg, int param) case SYSTEM_EVENT_USERIDLE: { if (Parameters.BlankWhenIdle) - TurnOffDisplay(false, false, true); + { + if (AdhereTopology) + { + if (TopologyEnabled) + TurnOffDisplay(false, false, true); + } + else + TurnOffDisplay(false, false, true); + } }break; case SYSTEM_EVENT_USERBUSY: { if (Parameters.BlankWhenIdle) - TurnOnDisplay(true); + { + if (AdhereTopology) + { + if (TopologyEnabled) + TurnOnDisplay(true); + } + else + TurnOnDisplay(true); + } }break; case SYSTEM_EVENT_BOOT: { if (Parameters.SetHDMIInputOnResume) - SetDisplayHdmiInput(Parameters.SetHDMIInputOnResumeToNumber); + { + if (AdhereTopology) + { + if(TopologyEnabled) + SetDisplayHdmiInput(Parameters.SetHDMIInputOnResumeToNumber); + } + else + SetDisplayHdmiInput(Parameters.SetHDMIInputOnResumeToNumber); + } }break; case SYSTEM_EVENT_UNBLANK: { TurnOnDisplay(false); }break; + case SYSTEM_EVENT_TOPOLOGY: + { + if (AdhereTopology) + { + if (TopologyEnabled) + TurnOnDisplay(true); + else + TurnOffDisplay(false, false, false); + } + }break; default:break; } } diff --git a/LGTV Companion Setup/Product.wxs b/LGTV Companion Setup/Product.wxs index 2cc8fdc..f3489c3 100644 --- a/LGTV Companion Setup/Product.wxs +++ b/LGTV Companion Setup/Product.wxs @@ -3,7 +3,7 @@ - + diff --git a/LGTV Companion UI/LGTV Companion UI.cpp b/LGTV Companion UI/LGTV Companion UI.cpp index 03da953..6b5bc86 100644 --- a/LGTV Companion UI/LGTV Companion UI.cpp +++ b/LGTV Companion UI/LGTV Companion UI.cpp @@ -130,7 +130,11 @@ CHANGELOG - Some additional help texts in the options dialog - Bugfixes and optimisations - Todo: Option to manage on active display outputs only + v 1.8.0 - Option to conform to windows monitor topology (active display outputs only) + + TODO: + + v 1.9.0 - Enhanced support for GameStream/Moonlight/SteamLink LICENSE Copyright (c) 2021-2022 Jörgen Persson @@ -176,10 +180,15 @@ HBRUSH hBackbrush; HFONT hEditfont; HFONT hEditMediumfont; HFONT hEditSmallfont; +HFONT hEditMediumBoldfont; HMENU hPopupMeuMain; HICON hOptionsIcon; +HICON hTopologyIcon; +HICON hCogIcon; HANDLE hPipe = INVALID_HANDLE_VALUE; WSADATA WSAData; +int iTopConfPhase; +int iTopConfDisplay; //Application entry point int APIENTRY wWinMain(_In_ HINSTANCE Instance, @@ -213,6 +222,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE Instance, if (ReadConfigFile()) ReadDeviceConfig(); } + catch (std::exception const& e) { wstring s = L"Error when reading configuration. Service is terminating. Error: "; s += widen(e.what()); @@ -221,6 +231,15 @@ int APIENTRY wWinMain(_In_ HINSTANCE Instance, return false; } + // tweak prefs conf + bool bTop = false; + for (auto m : Devices) + { + if (m.UniqueDeviceKey != "") + bTop = true; + } + Prefs.AdhereTopology = bTop ? Prefs.AdhereTopology : false; + //parse and execute command line parameters when applicable and then exit if (Devices.size() > 0 && CommandLineParameters.size() > 0) { @@ -234,6 +253,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE Instance, hEditfont = CreateFont(26, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH, TEXT("Calibri")); hEditMediumfont = CreateFont(20, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH, TEXT("Calibri")); hEditSmallfont = CreateFont(18, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH, TEXT("Calibri")); + hEditMediumBoldfont = CreateFont(20, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH, TEXT("Calibri")); hPopupMeuMain = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_BUTTONMENU)); INITCOMMONCONTROLSEX icex; // Structure for control initialization. @@ -243,6 +263,8 @@ int APIENTRY wWinMain(_In_ HINSTANCE Instance, InitCommonControlsEx(&icex); hOptionsIcon = (HICON)LoadImageW(hInstance, MAKEINTRESOURCE(IDI_ICON2), IMAGE_ICON, 25, 25, LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_SHARED); + hTopologyIcon = (HICON)LoadImageW(hInstance, MAKEINTRESOURCE(IDI_ICON4), IMAGE_ICON, 48, 48, LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_SHARED); + hCogIcon = (HICON)LoadImageW(hInstance, MAKEINTRESOURCE(IDI_ICON3), IMAGE_ICON, 25, 25, LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_SHARED); WSAStartup(MAKEWORD(2, 2), &WSAData); @@ -271,11 +293,15 @@ int APIENTRY wWinMain(_In_ HINSTANCE Instance, //clean up DeleteObject(hBackbrush); + DeleteObject(hEditMediumBoldfont); DeleteObject(hEditfont); DeleteObject(hEditMediumfont); DeleteObject(hEditSmallfont); DestroyMenu(hPopupMeuMain); DestroyIcon(hOptionsIcon); + DestroyIcon(hTopologyIcon); + DestroyIcon(hCogIcon); + WSACleanup(); return (int)msg.wParam; @@ -295,6 +321,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) SendDlgItemMessage(hWnd, IDC_DONATE, WM_SETFONT, (WPARAM)hEditSmallfont, MAKELPARAM(TRUE, 0)); SendDlgItemMessage(hWnd, IDC_SPLIT, WM_SETFONT, (WPARAM)hEditSmallfont, MAKELPARAM(TRUE, 0)); SendDlgItemMessage(hWnd, IDOK, WM_SETFONT, (WPARAM)hEditSmallfont, MAKELPARAM(TRUE, 0)); + SendDlgItemMessage(hWnd, IDC_OPTIONS, WM_SETFONT, (WPARAM)hEditMediumfont, MAKELPARAM(TRUE, 0)); SendMessage(GetDlgItem(hWnd, IDC_COMBO), (UINT)CB_RESETCONTENT, (WPARAM)0, (LPARAM)0); SendMessage(GetDlgItem(hWnd, IDC_COMBO), (UINT)CB_SETCURSEL, (WPARAM)-1, (LPARAM)0); @@ -314,8 +341,13 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) SetDlgItemText(hWnd, IDC_SPLIT, L"C&onfigure"); } else + { + EnableWindow(GetDlgItem(hWnd, IDC_COMBO), false); SetDlgItemText(hWnd, IDC_SPLIT, L"&Scan"); + } SendMessageW(GetDlgItem(hWnd, IDC_OPTIONS), BM_SETIMAGE, IMAGE_ICON, (LPARAM)hOptionsIcon); +// SendMessageW(GetDlgItem(hWnd, IDC_SPLIT), BM_SETIMAGE, IMAGE_ICON, (LPARAM)hCogIcon); + }break; case APP_NEW_VERSION: { @@ -326,7 +358,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) HWND hDeviceWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DEVICE), hWnd, (DLGPROC)DeviceWndProc); SetWindowText(hDeviceWnd, DEVICEWINDOW_TITLE_ADD); SetWindowText(GetDlgItem(hDeviceWnd, IDOK), L"&Add"); - CheckDlgButton(hDeviceWnd, IDC_RADIO1, BST_CHECKED); + CheckDlgButton(hDeviceWnd, IDC_RADIO2, BST_CHECKED); EnableWindow(GetDlgItem(hDeviceWnd, IDC_SUBNET), false); SetWindowText(GetDlgItem(hDeviceWnd, IDC_SUBNET), WOL_DEFAULTSUBNET); @@ -530,6 +562,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) EnableWindow(GetDlgItem(hWnd, IDC_CHECK_ENABLE), false); SendMessage(GetDlgItem(hWnd, IDC_COMBO), (UINT)CB_RESETCONTENT, (WPARAM)0, (LPARAM)0); SendMessage(GetDlgItem(hWnd, IDC_COMBO), (UINT)CB_SETCURSEL, (WPARAM)-1, (LPARAM)0); + EnableWindow(GetDlgItem(hWnd, IDC_COMBO), false); SetDlgItemText(hWnd, IDC_SPLIT, L"&Scan"); } else @@ -546,6 +579,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) SendMessage(GetDlgItem(hWnd, IDC_COMBO), (UINT)CB_SETCURSEL, (WPARAM)j, (LPARAM)0); CheckDlgButton(hWnd, IDC_CHECK_ENABLE, Devices[j].Enabled ? BST_CHECKED : BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_CHECK_ENABLE), true); + EnableWindow(GetDlgItem(hWnd, IDC_COMBO), true); SetDlgItemText(hWnd, IDC_SPLIT, L"C&onfigure"); } else @@ -553,6 +587,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) CheckDlgButton(hWnd, IDC_CHECK_ENABLE, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_CHECK_ENABLE), false); SendMessage(GetDlgItem(hWnd, IDC_COMBO), (UINT)CB_SETCURSEL, (WPARAM)-1, (LPARAM)0); + EnableWindow(GetDlgItem(hWnd, IDC_COMBO), false); SetDlgItemText(hWnd, IDC_SPLIT, L"&Scan"); } } @@ -900,6 +935,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } DestroyWindow(hWnd); }break; + case WM_DESTROY: { PostQuitMessage(0); @@ -1046,6 +1082,7 @@ LRESULT CALLBACK DeviceWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP int ind = (int)SendMessage(GetDlgItem(hParentWnd, IDC_COMBO), (UINT)CB_DELETESTRING, (WPARAM)sel, (LPARAM)0); SendMessage(GetDlgItem(hParentWnd, IDC_COMBO), (UINT)CB_INSERTSTRING, (WPARAM)sel, (LPARAM)widen(Devices[sel].Name).c_str()); SendMessage(GetDlgItem(hParentWnd, IDC_COMBO), (UINT)CB_SETCURSEL, (WPARAM)sel, (LPARAM)0); + EnableWindow(GetDlgItem(hParentWnd, IDC_COMBO), true); EnableWindow(GetDlgItem(hParentWnd, IDOK), true); } else //adding a new device @@ -1080,6 +1117,7 @@ LRESULT CALLBACK DeviceWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP { SendMessage(GetDlgItem(hParentWnd, IDC_COMBO), (UINT)CB_SETCURSEL, (WPARAM)index, (LPARAM)0); CheckDlgButton(hParentWnd, IDC_CHECK_ENABLE, BST_CHECKED); + EnableWindow(GetDlgItem(hParentWnd, IDC_COMBO), true); EnableWindow(GetDlgItem(hParentWnd, IDC_CHECK_ENABLE), true); SetDlgItemText(hParentWnd, IDC_SPLIT, L"C&onfigure"); @@ -1145,7 +1183,11 @@ LRESULT CALLBACK DeviceWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lP case WM_CTLCOLORSTATIC: { HDC hdcStatic = (HDC)wParam; - if ((HWND)lParam == GetDlgItem(hWnd, IDC_CHECK_ENABLE)) + if ((HWND)lParam == GetDlgItem(hWnd, IDC_HDMI_INPUT_NUMBER_CHECKBOX) + || (HWND)lParam == GetDlgItem(hWnd, IDC_SET_HDMI_INPUT_CHECKBOX) + || (HWND)lParam == GetDlgItem(hWnd, IDC_RADIO1) + || (HWND)lParam == GetDlgItem(hWnd, IDC_RADIO2) + || (HWND)lParam == GetDlgItem(hWnd, IDC_RADIO3)) { SetBkMode(hdcStatic, TRANSPARENT); } @@ -1190,6 +1232,8 @@ LRESULT CALLBACK OptionsWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l wstring query = L"Event/System[EventID=1074]"; vector str; + SendDlgItemMessage(hWnd, IDC_STATIC_C, WM_SETFONT, (WPARAM)hEditSmallfont, MAKELPARAM(TRUE, 0)); + SendDlgItemMessage(hWnd, IDC_TIMEOUT, WM_SETFONT, (WPARAM)hEditMediumfont, MAKELPARAM(TRUE, 0)); SendDlgItemMessage(hWnd, IDC_LIST, WM_SETFONT, (WPARAM)hEditMediumfont, MAKELPARAM(TRUE, 0)); SendDlgItemMessage(hWnd, IDC_SPIN, UDM_SETRANGE, (WPARAM)NULL, MAKELPARAM(100, 1)); @@ -1295,7 +1339,7 @@ LRESULT CALLBACK OptionsWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l CheckDlgButton(hWnd, IDC_CHECK_BLANK, Prefs.BlankScreenWhenIdle ? BST_CHECKED : BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_EDIT_BLANK), Prefs.BlankScreenWhenIdle); CheckDlgButton(hWnd, IDC_CHECK_RDPBLANK, Prefs.PowerOffDuringRDP ? BST_CHECKED : BST_UNCHECKED); - + CheckDlgButton(hWnd, IDC_CHECK_TOPOLOGY, Prefs.AdhereTopology ? BST_CHECKED : BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDOK), true); }break; case WM_COMMAND: @@ -1335,6 +1379,38 @@ LRESULT CALLBACK OptionsWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l EnableWindow(GetDlgItem(hWnd, IDOK), true); } }break; + case IDC_CHECK_TOPOLOGY: + { + bool found = false; + if (Devices.size() == 0) + { + MessageBox(hWnd, L"Please configure devices before enabling and configuring this option", L"Error", MB_ICONEXCLAMATION | MB_OK); + CheckDlgButton(hWnd, IDC_CHECK_TOPOLOGY, BST_UNCHECKED); + } + else + { + for (auto& k : Devices) + { + if (k.UniqueDeviceKey != "") + found = true; + } + + if (found) + { + EnableWindow(GetDlgItem(hWnd, IDOK), true); + } + else + { + HWND hConfigureWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_CONFIGURE_TOPOLOGY), hWnd, (DLGPROC)ConfigureTopologyWndProc); + EnableWindow(hWnd, false); + ShowWindow(hConfigureWnd, SW_SHOW); + } + } + + + + }break; + case IDC_LOGGING: case IDC_AUTOUPDATE: case IDC_CHECK_RDPBLANK: @@ -1360,6 +1436,7 @@ LRESULT CALLBACK OptionsWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l Prefs.BlankScreenWhenIdle = IsDlgButtonChecked(hWnd, IDC_CHECK_BLANK) == BST_CHECKED; Prefs.BlankScreenWhenIdleDelay = atoi(narrow(GetWndText(GetDlgItem(hWnd, IDC_EDIT_BLANK))).c_str()); Prefs.PowerOffDuringRDP = IsDlgButtonChecked(hWnd, IDC_CHECK_RDPBLANK) == BST_CHECKED; + Prefs.AdhereTopology = IsDlgButtonChecked(hWnd, IDC_CHECK_TOPOLOGY) == BST_CHECKED; int count = ListView_GetItemCount(GetDlgItem(hWnd, IDC_LIST)); Prefs.EventLogRestartString.clear(); @@ -1422,16 +1499,58 @@ LRESULT CALLBACK OptionsWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l str += L"log.txt"; ShellExecute(NULL, L"open", str.c_str(), NULL, DataPath.c_str(), SW_SHOW); } + //clear log + if (wParam == IDC_SYSLINK2) + { + wstring str = DataPath; + str += L"log.txt"; + wstring mess = L"Do you want to clear the log?\n\n"; + mess += str; + if (MessageBox(hWnd, mess.c_str(), L"Clear log?", MB_YESNO | MB_ICONQUESTION) == IDYES) + { + CommunicateWithService("-clearlog"); + } + } // explain the restart words if (wParam == IDC_SYSLINK3) { - MessageBox(hWnd, L"This application rely on events in the windows event log to determine whether a reboot or shutdown was initiated by the user.\n\nThese events are localised in the language of your operating system, and the user must therefore assist with manually indicating which strings refers to the system restarting.\n\nPlease put a checkmark for every string which refers to 'restart'", L"Information", MB_OK | MB_ICONINFORMATION); + MessageBox(hWnd, L"This application rely on events in the windows event log to determine whether a reboot or shutdown was initiated by the user." + "\n\nThese events are localised in the language of your operating system, and the user must therefore assist with manually indicating which " + "strings refers to the system restarting.\n\nPlease put a checkmark for every string which refers to 'restart'", + L"Information", MB_OK | MB_ICONINFORMATION); } // explain the power saving options if (wParam == IDC_SYSLINK5) { - MessageBox(hWnd, L"The option to automatically blank the screen triggers in the absence of user input from keyboard, mouse and/or controllers.The difference, when compared to both the screensaver and windows power plan settings, is that those OS implemented power saving functions utilize more obscured variables for determining user idle / busy states, and which can also be programmatically overridden f.e. by games, media players, production software or your web browser, In short, and simplified, this option is a more aggressively configured screen and power saver. Plese note that this feature is incompatible with-, and will therefore be disabled, while the system is remoted into, using RDP.\n\nThe option to turn off the device while the system is being remoted into, using RDP, is useful to avoid the screen displaying a static login screen during a remote RDP session. There is a delay of 10 seconds after RDP connection. Please note that depending on the configuration of your system (primarily time to turn off screen in power options) there may be occasions where the display cannot be woken by using the local mouse and keyboard and you must rely on the remote to see the login screen. It is recommended to combine this option with a short (<30 minutes) time to turn off displays in Windows Power Plan Options.", L"Information", MB_OK | MB_ICONINFORMATION); + MessageBox(hWnd, L"The option to automatically blank the screen triggers in the absence of user input from keyboard, mouse and/or controllers." + "The difference, when compared to both the screensaver and windows power plan settings, is that those OS implemented power saving functions " + "utilize more obscured variables for determining user idle / busy states, and which can also be programmatically overridden f.e. by games, " + "media players, production software or your web browser, In short, and simplified, this option is a more aggressively configured screen and " + "power saver. Plese note that this feature is incompatible with-, and will therefore be disabled, while the system is remoted into, using " + "RDP.\n\nThe option to turn off the device while the system is being remoted into, using RDP, is useful to avoid the screen displaying a static " + "login screen during a remote RDP session. There is a delay of 10 seconds after RDP connection. Please note that depending on the configuration " + "of your system (primarily time to turn off screen in power options) there may be occasions where the display cannot be woken by using the local " + "mouse and keyboard and you must rely on the remote to see the login screen. It is recommended to combine this option with a short (<30 minutes) " + "time to turn off displays in Windows Power Plan Options.\n\nThe option to automatically conform to the windows monitor topology ensures that " + "power state of individual devices will mztch the enabled/disabled state in the Windows monitor configuration, f e " + "when an HDMI-output and associated device is disabled in the graphics card configuration the associated device will also power off.", + L"Information", MB_OK | MB_ICONINFORMATION); } + if (wParam == IDC_SYSLINK_CONF) + { + if (Devices.size() == 0) + { + MessageBox(hWnd, L"Please configure devices before enabling and configuring this option", L"Error", MB_ICONEXCLAMATION | MB_OK); + CheckDlgButton(hWnd, IDC_CHECK_TOPOLOGY, BST_UNCHECKED); + } + else + { + HWND hConfigureWnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_CONFIGURE_TOPOLOGY), hWnd, (DLGPROC)ConfigureTopologyWndProc); + EnableWindow(hWnd, false); + ShowWindow(hConfigureWnd, SW_SHOW); + } + } + }break; case LVN_ITEMCHANGED: { @@ -1457,10 +1576,298 @@ LRESULT CALLBACK OptionsWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l case WM_CTLCOLORSTATIC: { HDC hdcStatic = (HDC)wParam; - if ((HWND)lParam == GetDlgItem(hWnd, IDC_CHECK_ENABLE)) + SetTextColor(hdcStatic, COLORREF(COLOR_STATIC)); + if ((HWND)lParam == GetDlgItem(hWnd, IDC_CHECK_BLANK) + || (HWND)lParam == GetDlgItem(hWnd, IDC_CHECK_RDPBLANK) + || (HWND)lParam == GetDlgItem(hWnd, IDC_LOGGING) + || (HWND)lParam == GetDlgItem(hWnd, IDC_AUTOUPDATE)) + { + SetBkMode(hdcStatic, TRANSPARENT); + } + return(INT_PTR)hBackbrush; + }break; + + case WM_PAINT: + { + RECT rc = { 0 }; + + GetClientRect(hWnd, &rc); + + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hWnd, &ps); + FillRect(hdc, &rc, (HBRUSH)hBackbrush); + + EndPaint(hWnd, &ps); + }break; + + case WM_CLOSE: + { + EndDialog(hWnd, 0); + }break; + + default:break; + } + return 0; +} + +// Process messages for the options window +LRESULT CALLBACK ConfigureTopologyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + { + SendDlgItemMessage(hWnd, IDC_COMBO, WM_SETFONT, (WPARAM)hEditfont, MAKELPARAM(TRUE, 0)); + SendDlgItemMessage(hWnd, IDC_STATIC_NO_1, WM_SETFONT, (WPARAM)hEditfont, MAKELPARAM(TRUE, 0)); + SendDlgItemMessage(hWnd, IDC_STATIC_NO_2, WM_SETFONT, (WPARAM)hEditfont, MAKELPARAM(TRUE, 0)); + SendDlgItemMessage(hWnd, IDC_STATIC_NO_3, WM_SETFONT, (WPARAM)hEditfont, MAKELPARAM(TRUE, 0)); + SendDlgItemMessage(hWnd, IDC_STATIC_NO_4, WM_SETFONT, (WPARAM)hEditfont, MAKELPARAM(TRUE, 0)); + SendDlgItemMessage(hWnd, IDC_STATIC_NO_5, WM_SETFONT, (WPARAM)hEditfont, MAKELPARAM(TRUE, 0)); + SendDlgItemMessage(hWnd, IDC_STATIC_NO_6, WM_SETFONT, (WPARAM)hEditfont, MAKELPARAM(TRUE, 0)); + + SendDlgItemMessage(hWnd, IDC_STATIC_T_11, WM_SETFONT, (WPARAM)hEditSmallfont, MAKELPARAM(TRUE, 0)); + SendDlgItemMessage(hWnd, IDC_STATIC_T_12, WM_SETFONT, (WPARAM)hEditSmallfont, MAKELPARAM(TRUE, 0)); + SendDlgItemMessage(hWnd, IDC_STATIC_T_13, WM_SETFONT, (WPARAM)hEditSmallfont, MAKELPARAM(TRUE, 0)); + SendDlgItemMessage(hWnd, IDC_STATIC_T_14, WM_SETFONT, (WPARAM)hEditSmallfont, MAKELPARAM(TRUE, 0)); + SendDlgItemMessage(hWnd, IDC_STATIC_T_15, WM_SETFONT, (WPARAM)hEditSmallfont, MAKELPARAM(TRUE, 0)); + SendDlgItemMessage(hWnd, IDC_STATIC_T_16, WM_SETFONT, (WPARAM)hEditSmallfont, MAKELPARAM(TRUE, 0)); + SendDlgItemMessage(hWnd, IDC_STATIC_STATUS_1, WM_SETFONT, (WPARAM)hEditMediumfont, MAKELPARAM(TRUE, 0)); + SendDlgItemMessage(hWnd, IDC_STATIC_STATUS_2, WM_SETFONT, (WPARAM)hEditMediumBoldfont, MAKELPARAM(TRUE, 0)); + SetWindowText(GetDlgItem(hWnd, IDC_STATIC_STATUS_2), L"Not configured!"); + for (auto& k : Devices) + { + if (k.UniqueDeviceKey != "") + { + SetWindowText(GetDlgItem(hWnd, IDC_STATIC_STATUS_2), L"Configuration OK!"); + } + } + + + SendMessage(GetDlgItem(hWnd, IDC_COMBO), (UINT)CB_RESETCONTENT, (WPARAM)0, (LPARAM)0); + SendMessage(GetDlgItem(hWnd, IDC_COMBO), (UINT)CB_SETCURSEL, (WPARAM)-1, (LPARAM)0); + + if (Devices.size() > 0) + { + for (const auto& item : Devices) + { + stringstream s; + s << item.DeviceId << ": " << item.Name << "(" << item.IP << ")"; + SendMessage(GetDlgItem(hWnd, IDC_COMBO), (UINT)CB_ADDSTRING, (WPARAM)0, (LPARAM)widen(s.str()).c_str()); + } + SendMessage(GetDlgItem(hWnd, IDC_COMBO), (UINT)CB_SETCURSEL, (WPARAM)0, (LPARAM)0); + } + SendMessage(hWnd, APP_TOP_PHASE_1, NULL, NULL); + iTopConfDisplay = 0; + }break; + case APP_TOP_PHASE_1: + { + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_1), true); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_2), true); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_3), true); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_4), true); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_11), true); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_12), true); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_13), true); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_14), true); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_5), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_15), false); + EnableWindow(GetDlgItem(hWnd, IDC_COMBO), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_6), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_16), false); + SetWindowText(GetDlgItem(hWnd, IDOK), L"&Start"); + iTopConfPhase = 1; + }break; + case APP_TOP_PHASE_2: + { + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_1), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_2), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_3), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_4), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_11), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_12), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_13), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_14), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_5), true); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_15), true); + EnableWindow(GetDlgItem(hWnd, IDC_COMBO), true); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_6), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_16), false); + SetWindowText(GetDlgItem(hWnd, IDC_STATIC_STATUS_2), L"Updating configuration!"); + SetWindowText(GetDlgItem(hWnd, IDOK), L"&Next"); + iTopConfPhase = 2; + }break; + case APP_TOP_PHASE_3: + { + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_1), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_2), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_3), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_4), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_11), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_12), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_13), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_14), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_5), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_15), false); + EnableWindow(GetDlgItem(hWnd, IDC_COMBO), false); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_NO_6), true); + EnableWindow(GetDlgItem(hWnd, IDC_STATIC_T_16), true); + SetWindowText(GetDlgItem(hWnd, IDOK), L"&Finish"); + iTopConfPhase = 3; + for (auto& k : Devices) + { + if (k.UniqueDeviceKey_Temp != "") + { + SetWindowText(GetDlgItem(hWnd, IDC_STATIC_STATUS_2), L"All OK!"); + } + } + + }break; + case APP_TOP_NEXT_DISPLAY: + { + vector displays = QueryDisplays(); + if (displays.size() > iTopConfDisplay) + { + RECT DialogRect; + RECT DisplayRect; + GetWindowRect(hWnd, &DialogRect); + DisplayRect = displays[iTopConfDisplay].monitorinfo.rcWork; + + int x = DisplayRect.left + (DisplayRect.right - DisplayRect.left) / 2 - (DialogRect.right - DialogRect.left) / 2; + int y = DisplayRect.top + (DisplayRect.bottom - DisplayRect.top) / 2 - (DialogRect.bottom - DialogRect.top) / 2; + int cx = DialogRect.right - DialogRect.left; + int cy = DialogRect.bottom - DialogRect.top; + MoveWindow(hWnd, x, y, cx, cy, true); + } + }break; + + case WM_COMMAND: + { + switch (HIWORD(wParam)) + { + case BN_CLICKED: + { + switch (LOWORD(wParam)) + { + + case IDOK: + { + + switch (iTopConfPhase) // three phases - intro, match displays, finalise + { + case 1: + { + vector displays = QueryDisplays(); + // No WebOs devices attached + if (displays.size() == 0) + { + MessageBox(hWnd, L"To configure your devices, ensure that all your WebOS-devices are powered ON, connected to to your PC and enabled (with an extended desktop in case of multiple displays).", L"No WebOS devices detected", MB_OK | MB_ICONWARNING); + break; + } + // If exactly one physical device connected/enabled and exactly one device cofigured it is considered an automatic match + else if (Devices.size() == 1 && displays.size() == 1) + { + if (MessageBox(hWnd, L"Your device can be automatically configured.\n\nDo you want to accept the automatic configuration?", L"Automatic match", MB_YESNO) == IDYES) + { + Devices[0].UniqueDeviceKey_Temp = narrow(displays[0].target.monitorDevicePath); + SendMessage(hWnd, APP_TOP_PHASE_3, NULL, NULL); + SetWindowText(GetDlgItem(hWnd, IDC_STATIC_STATUS_2), L"All OK!"); + break; + } + } + SendMessage(hWnd, APP_TOP_PHASE_2, NULL, NULL); + SendMessage(hWnd, APP_TOP_NEXT_DISPLAY, NULL, NULL); + }break; + case 2: + { + vector displays = QueryDisplays(); + int sel = (int)(SendMessage(GetDlgItem(hWnd, IDC_COMBO), (UINT)CB_GETCURSEL, (WPARAM)0, (LPARAM)0)); + if (sel == CB_ERR || Devices.size() <= sel) + break; + Devices[sel].UniqueDeviceKey_Temp = narrow(displays[iTopConfDisplay].target.monitorDevicePath); + + iTopConfDisplay++; + if (iTopConfDisplay >= displays.size()) // all displays iterated + { + SendMessage(hWnd, APP_TOP_PHASE_3, NULL, NULL); + } + else // more displays are connected + { + SendMessage(hWnd, APP_TOP_NEXT_DISPLAY, NULL, NULL); + } + + }break; + case 3: + { + for (auto& k : Devices) + { + k.UniqueDeviceKey = k.UniqueDeviceKey_Temp; + } + EndDialog(hWnd, 0); + EnableWindow(GetParent(hWnd), true); + EnableWindow(GetDlgItem(GetParent(hWnd), IDOK), true); + }break; + default:break; + } + }break; + case IDCANCEL: + { + bool conf = false; + for (auto& k : Devices) + { + if (k.UniqueDeviceKey != "") + { + conf = true; + break; + } + } + if (!conf) + { + CheckDlgButton(GetParent(hWnd), IDC_CHECK_TOPOLOGY, BST_UNCHECKED); + } + EndDialog(hWnd, 0); + EnableWindow(GetParent(hWnd), true); + }break; + default:break; + } + }break; + default:break; + } + }break; + case WM_CTLCOLORSTATIC: + { + HDC hdcStatic = (HDC)wParam; + if ((HWND)lParam == GetDlgItem(hWnd, IDC_STATIC_NO_1) + || (HWND)lParam == GetDlgItem(hWnd, IDC_STATIC_NO_2) + || (HWND)lParam == GetDlgItem(hWnd, IDC_STATIC_NO_3) + || (HWND)lParam == GetDlgItem(hWnd, IDC_STATIC_NO_4) + || (HWND)lParam == GetDlgItem(hWnd, IDC_STATIC_T_1) + || (HWND)lParam == GetDlgItem(hWnd, IDC_STATIC_T_2) + || (HWND)lParam == GetDlgItem(hWnd, IDC_STATIC_T_3) + || (HWND)lParam == GetDlgItem(hWnd, IDC_STATIC_T_4) + || (HWND)lParam == GetDlgItem(hWnd, IDC_STATIC_STATUS_1) + || (HWND)lParam == GetDlgItem(hWnd, IDC_STATIC_STATUS_2)) { SetBkMode(hdcStatic, TRANSPARENT); } + if ((HWND)lParam == GetDlgItem(hWnd, IDC_STATIC_STATUS_2)) + { + wstring s = GetWndText(GetDlgItem(hWnd, IDC_STATIC_STATUS_2)); + if(s.find(L"OK!") != wstring::npos) + SetTextColor(hdcStatic, COLORREF(COLOR_GREEN)); + else if (s.find(L"Updating") != wstring::npos) + SetTextColor(hdcStatic, COLORREF(COLOR_BLUE)); + else + SetTextColor(hdcStatic, COLORREF(COLOR_RED)); + } + + else if ((HWND)lParam == GetDlgItem(hWnd, IDC_STATIC_NO_1) + || (HWND)lParam == GetDlgItem(hWnd, IDC_STATIC_NO_2) + || (HWND)lParam == GetDlgItem(hWnd, IDC_STATIC_NO_3) + || (HWND)lParam == GetDlgItem(hWnd, IDC_STATIC_NO_4)) + SetTextColor(hdcStatic, COLORREF(COLOR_BLUE)); + else + SetTextColor(hdcStatic, COLORREF(COLOR_STATIC)); + return(INT_PTR)hBackbrush; }break; @@ -1487,6 +1894,7 @@ LRESULT CALLBACK OptionsWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l return 0; } + // If the application is already running, send the command line parameters to that other process bool MessageExistingProcess(wstring CmdLine) { @@ -1584,6 +1992,10 @@ bool ReadConfigFile() if (!j.empty() && j.is_boolean()) Prefs.PowerOffDuringRDP = j.get(); + j = jsonPrefs[JSON_PREFS_NODE][JSON_ADHERETOPOLOGY]; + if (!j.empty() && j.is_boolean()) + Prefs.AdhereTopology = j.get(); + return true; } } @@ -1686,6 +2098,9 @@ void ReadDeviceConfig() if (item.value()["IP"].is_string()) params.IP = item.value()["IP"].get(); + if (item.value()["UniqueDeviceKey"].is_string()) + params.UniqueDeviceKey = item.value()["UniqueDeviceKey"].get(); + if (item.value()["HDMIinputcontrol"].is_boolean()) params.HDMIinputcontrol = item.value()["HDMIinputcontrol"].get(); @@ -1839,6 +2254,7 @@ void WriteConfigFile(void) prefs[JSON_PREFS_NODE][JSON_IDLEBLANK] = (bool)Prefs.BlankScreenWhenIdle; prefs[JSON_PREFS_NODE][JSON_IDLEBLANKDELAY] = (int)Prefs.BlankScreenWhenIdleDelay; prefs[JSON_PREFS_NODE][JSON_RDP_POWEROFF] = (bool)Prefs.PowerOffDuringRDP; + prefs[JSON_PREFS_NODE][JSON_ADHERETOPOLOGY] = (bool)Prefs.AdhereTopology; for (auto& item : Prefs.EventLogRestartString) prefs[JSON_PREFS_NODE][JSON_EVENT_RESTART_STRINGS].push_back(item); @@ -1865,6 +2281,8 @@ void WriteConfigFile(void) prefs[dev.str()]["SessionKey"] = item.SessionKey; else prefs[dev.str()]["SessionKey"] = ""; + if (item.UniqueDeviceKey != "") + prefs[dev.str()]["UniqueDeviceKey"] = item.UniqueDeviceKey; prefs[dev.str()]["HDMIinputcontrol"] = (bool)item.HDMIinputcontrol; prefs[dev.str()]["OnlyTurnOffIfCurrentHDMIInputNumberIs"] = item.OnlyTurnOffIfCurrentHDMIInputNumberIs; @@ -1972,4 +2390,85 @@ void VersionCheckThread(HWND hWnd) } } return; +} + + +vector QueryDisplays() +{ + vector targets; + + //populate targets struct with information about attached displays + EnumDisplayMonitors(NULL, NULL, meproc, (LPARAM) & targets); + + return targets; + + +} +static BOOL CALLBACK meproc(HMONITOR hMonitor, HDC hdc, LPRECT lprcMonitor, LPARAM pData) +{ + if (!pData) + return false; + vector * targets = (vector *) pData; + UINT32 requiredPaths, requiredModes; + vector paths; + vector modes; + MONITORINFOEX mi; + LONG isError = ERROR_INSUFFICIENT_BUFFER; + + ZeroMemory(&mi, sizeof(mi)); + mi.cbSize = sizeof(mi); + GetMonitorInfo(hMonitor, &mi); +// wprintf(L"DisplayDevice: %s\n", mi.szDevice); + + isError = GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &requiredPaths, &requiredModes); + if (isError) + { + targets->clear(); + return false; + } + paths.resize(requiredPaths); + modes.resize(requiredModes); + + isError = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &requiredPaths, paths.data(), &requiredModes, modes.data(), NULL); + if (isError) + { + targets->clear(); + return false; + } + paths.resize(requiredPaths); + modes.resize(requiredModes); + + for (auto& p : paths) + { + DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName; + sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + sourceName.header.size = sizeof(sourceName); + sourceName.header.adapterId = p.sourceInfo.adapterId; + sourceName.header.id = p.sourceInfo.id; + + DisplayConfigGetDeviceInfo(&sourceName.header); + if (wcscmp(mi.szDevice, sourceName.viewGdiDeviceName) == 0) + { + DISPLAYCONFIG_TARGET_DEVICE_NAME name; + name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; + name.header.size = sizeof(name); + name.header.adapterId = p.sourceInfo.adapterId; + name.header.id = p.targetInfo.id; + DisplayConfigGetDeviceInfo(&name.header); + wstring FriendlyName = name.monitorFriendlyDeviceName; + if (FriendlyName.find( L"LG TV") != wstring::npos) + { + DISPLAY_INFO di; + di.monitorinfo = mi; + di.hMonitor = hMonitor; + di.hdcMonitor = hdc; + di.rcMonitor2 = *(LPRECT)lprcMonitor; + di.target = name; + targets->push_back(di); + + } + } + } + return true; + } \ No newline at end of file diff --git a/LGTV Companion UI/LGTV Companion UI.h b/LGTV Companion UI/LGTV Companion UI.h index c70bcae..072bd5d 100644 --- a/LGTV Companion UI/LGTV Companion UI.h +++ b/LGTV Companion UI/LGTV Companion UI.h @@ -53,7 +53,7 @@ #define APPNAME_SHORT L"LGTVcomp" #define APPNAME_FULL L"LGTV Companion" -#define APP_VERSION L"1.7.0" +#define APP_VERSION L"1.8.0" #define WINDOW_CLASS_UNIQUE L"YOLOx0x0x0181818" #define NOTIFY_NEW_COMMANDLINE 1 @@ -66,10 +66,16 @@ #define JSON_PWRONTIMEOUT "PowerOnTimeOut" #define JSON_IDLEBLANK "BlankWhenIdle" #define JSON_IDLEBLANKDELAY "BlankWhenIdleDelay" +#define JSON_ADHERETOPOLOGY "AdhereDisplayTopology" #define DEFAULT_RESTART {"restart"} #define DEFAULT_SHUTDOWN {"shutdown","power off"} #define JSON_RDP_POWEROFF "PowerOffDuringRDP" +#define COLOR_STATIC 0x00555555 +#define COLOR_RED 0x00000099 +#define COLOR_GREEN 0x00009900 +#define COLOR_BLUE 0x00772222 + #define APP_MESSAGE_ADD WM_USER+1 #define APP_MESSAGE_MANAGE WM_USER+2 #define APP_MESSAGE_SCAN WM_USER+3 @@ -79,6 +85,10 @@ #define APP_MESSAGE_REMOVE WM_USER+7 #define APP_MESSAGE_APPLY WM_USER+8 #define APP_NEW_VERSION WM_USER+9 +#define APP_TOP_PHASE_1 WM_USER+10 +#define APP_TOP_PHASE_2 WM_USER+11 +#define APP_TOP_PHASE_3 WM_USER+12 +#define APP_TOP_NEXT_DISPLAY WM_USER+13 #define APP_CMDLINE_ON 1 #define APP_CMDLINE_OFF 2 @@ -110,6 +120,7 @@ struct PREFS { bool BlankScreenWhenIdle = false; int BlankScreenWhenIdleDelay = 10; bool PowerOffDuringRDP = false; + bool AdhereTopology = false; }; struct SESSIONPARAMETERS { std::string DeviceId; @@ -117,6 +128,9 @@ struct SESSIONPARAMETERS { std::vector MAC; std::string SessionKey; std::string Name; + std::string UniqueDeviceKey; + std::string UniqueDeviceKey_Temp; + // bool PowerAuto = true; // bool AwayAuto = true; bool Enabled = true; @@ -128,11 +142,20 @@ struct SESSIONPARAMETERS { bool SetHDMIInputOnResume = false; int SetHDMIInputOnResumeToNumber = 1; }; +struct DISPLAY_INFO { + DISPLAYCONFIG_TARGET_DEVICE_NAME target; + HMONITOR hMonitor; + HDC hdcMonitor; + RECT rcMonitor2; + MONITORINFOEX monitorinfo; +}; // Forward declarations of functions included in this code module: LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK DeviceWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK OptionsWndProc(HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK ConfigureTopologyWndProc(HWND, UINT, WPARAM, LPARAM); + bool MessageExistingProcess(std::wstring); bool ReadConfigFile(); void ReadDeviceConfig(); @@ -147,3 +170,5 @@ void CommunicateWithService(std::string); void WriteConfigFile(void); std::vector GetOwnIP(void); void VersionCheckThread(HWND); +static BOOL CALLBACK meproc(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData); +std::vector QueryDisplays(); \ No newline at end of file diff --git a/LGTV Companion UI/LGTV Companion UI.rc b/LGTV Companion UI/LGTV Companion UI.rc index c659704..195690e 100644 Binary files a/LGTV Companion UI/LGTV Companion UI.rc and b/LGTV Companion UI/LGTV Companion UI.rc differ diff --git a/LGTV Companion UI/LGTV Companion UI.vcxproj b/LGTV Companion UI/LGTV Companion UI.vcxproj index 11b5c78..45e264c 100644 --- a/LGTV Companion UI/LGTV Companion UI.vcxproj +++ b/LGTV Companion UI/LGTV Companion UI.vcxproj @@ -118,6 +118,7 @@ true _DEBUG;_WINDOWS;%(PreprocessorDefinitions) true + MultiThreadedDebug Windows @@ -154,6 +155,9 @@ + + + diff --git a/LGTV Companion UI/LGTV Companion UI.vcxproj.filters b/LGTV Companion UI/LGTV Companion UI.vcxproj.filters index 3806717..3e3f5bd 100644 --- a/LGTV Companion UI/LGTV Companion UI.vcxproj.filters +++ b/LGTV Companion UI/LGTV Companion UI.vcxproj.filters @@ -42,5 +42,14 @@ Resource Files + + Resource Files + + + Resource Files + + + Resource Files + \ No newline at end of file diff --git a/LGTV Companion UI/cog.ico b/LGTV Companion UI/cog.ico new file mode 100644 index 0000000..1e69ecd Binary files /dev/null and b/LGTV Companion UI/cog.ico differ diff --git a/LGTV Companion UI/go.ico b/LGTV Companion UI/go.ico new file mode 100644 index 0000000..88c85d5 Binary files /dev/null and b/LGTV Companion UI/go.ico differ diff --git a/LGTV Companion UI/icon3.ico b/LGTV Companion UI/icon3.ico new file mode 100644 index 0000000..5d06b9f Binary files /dev/null and b/LGTV Companion UI/icon3.ico differ diff --git a/LGTV Companion UI/resource.h b/LGTV Companion UI/resource.h index e23d9bf..75f4a6d 100644 --- a/LGTV Companion UI/resource.h +++ b/LGTV Companion UI/resource.h @@ -3,6 +3,7 @@ // Used by LGTV Companion UI.rc // #define IDC_MYICON 2 +#define IDCONFIGURE 3 #define IDD_LGTVCOMPANIONUI_DIALOG 102 #define IDR_MAINFRAME 128 #define IDD_MAIN 129 @@ -13,6 +14,9 @@ #define IDD_WAIT 133 #define IDI_ICON1 142 #define IDI_ICON2 143 +#define IDD_CONFIGURE_TOPOLOGY 144 +#define IDI_ICON4 149 +#define IDI_ICON3 150 #define IDC_COMBO 1000 #define IDC_SPLIT 1001 #define IDC_OPTIONS 1002 @@ -37,6 +41,7 @@ #define IDC_SYSLINK3 1019 #define IDC_SYSLINK5 1020 #define IDC_NEWVERSION 1021 +#define IDC_SYSLINK2 1021 #define IDC_RADIO1 1022 #define IDC_DONATE 1022 #define IDC_RADIO2 1023 @@ -48,7 +53,31 @@ #define IDC_SET_HDMI_INPUT_CHECKBOX 1029 #define IDC_TEST 1029 #define IDC_SET_HDMI_INPUT_NUMBER 1030 +#define IDC_CHECK_TOPOLOGY 1030 #define IDC_SET_HDMI_INPUT_SPIN 1031 +#define IDC_GO 1031 +#define IDC_STATIC_NO_1 1032 +#define IDC_STATIC_NO_2 1033 +#define IDC_STATIC_NO_3 1034 +#define IDC_STATIC_NO_4 1035 +#define IDC_STATIC_T_1 1036 +#define IDC_STATIC_T_11 1036 +#define IDC_STATIC_T_2 1037 +#define IDC_STATIC_T_12 1037 +#define IDC_STATIC_T_3 1038 +#define IDC_STATIC_T_14 1038 +#define IDC_STATIC_T_4 1039 +#define IDC_STATIC_T_16 1039 +#define IDC_STATIC_STATUS_1 1040 +#define IDC_STATIC_STATUS_2 1041 +#define IDC_STATIC_C 1042 +#define IDC_STATIC_T_5 1042 +#define IDC_STATIC_T_15 1042 +#define IDC_STATIC_NO_6 1043 +#define IDC_STATIC_T_13 1044 +#define IDC_SYSLINK_CONF 1044 +#define IDC_GO2 1045 +#define IDC_STATIC_NO_5 1046 #define ID_ADD_MANAGE 32771 #define ID_ADD_MANAGE32772 32772 #define ID_ADD_REMOVE 32773 @@ -69,13 +98,13 @@ #define IDC_STATIC -1 // Next default values for new objects -// +// #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NO_MFC 1 -#define _APS_NEXT_RESOURCE_VALUE 144 +#define _APS_NEXT_RESOURCE_VALUE 153 #define _APS_NEXT_COMMAND_VALUE 32788 -#define _APS_NEXT_CONTROL_VALUE 1030 +#define _APS_NEXT_CONTROL_VALUE 1045 #define _APS_NEXT_SYMED_VALUE 110 #endif #endif diff --git a/LGTV Companion User/Daemon.cpp b/LGTV Companion User/Daemon.cpp index d49b82b..af14f9d 100644 --- a/LGTV Companion User/Daemon.cpp +++ b/LGTV Companion User/Daemon.cpp @@ -20,6 +20,7 @@ PREFS Prefs; HANDLE hPipe = INVALID_HANDLE_VALUE; INT64 idToastFirstrun = NULL; INT64 idToastNewversion = NULL; +vector Devices; //Application entry point int APIENTRY wWinMain(_In_ HINSTANCE Instance, @@ -79,6 +80,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE Instance, // read the configuration file and init prefs try { ReadConfigFile(); + ReadDeviceConfig(); } catch (...) { CommunicateWithService("-daemon errorconfig"); @@ -103,6 +105,9 @@ int APIENTRY wWinMain(_In_ HINSTANCE Instance, SetTimer(hMainWnd, TIMER_MAIN, TIMER_MAIN_DELAY_WHEN_BUSY, (TIMERPROC)NULL); SetTimer(hMainWnd, TIMER_IDLE, Prefs.BlankScreenWhenIdleDelay * 60 * 1000, (TIMERPROC)NULL); } + if (Prefs.AdhereTopology) + SetTimer(hMainWnd, TIMER_TOPOLOGY, 8000, (TIMERPROC)NULL); + wstring startupmess = WindowTitle; startupmess += L" is running."; @@ -309,6 +314,13 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) else CommunicateWithService("-daemon remoteconnect"); Prefs.DisableSendingViaIPC = true; + return 0; + }break; + case TIMER_TOPOLOGY: + { + KillTimer(hWnd, TIMER_TOPOLOGY); + PostMessage(hWnd, USER_DISPLAYCHANGE, NULL, NULL); + return 0; }break; default:break; } @@ -376,7 +388,22 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) default:break; } - } + }break; + case USER_DISPLAYCHANGE: + { + CheckDisplayTopology(); + }break; + + case WM_DISPLAYCHANGE: + { + + if (Prefs.AdhereTopology) + { + PostMessage(hWnd, USER_DISPLAYCHANGE, NULL, NULL); + } + + }break; + case WM_WTSSESSION_CHANGE: { if (wParam == WTS_REMOTE_CONNECT) @@ -425,11 +452,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PostQuitMessage(0); break; + }break; + default:break; } - default: - return 0; - } - return 0; + return DefWindowProc(hWnd, message, wParam, lParam); } // If the application is already running, tell other process to exit @@ -496,6 +522,10 @@ bool ReadConfigFile() if (!j.empty() && j.is_number()) Prefs.BlankScreenWhenIdleDelay = j.get(); + j = jsonPrefs[JSON_PREFS_NODE][JSON_ADHERETOPOLOGY]; + if (!j.empty() && j.is_boolean()) + Prefs.AdhereTopology = j.get(); + return true; } } @@ -535,13 +565,13 @@ string narrow(wstring sInput) { } // Send the commandline to the service -void CommunicateWithService(string input) +void CommunicateWithService(string input, bool OverrideDisable) { DWORD dwWritten; if (input == "") return; - if (!Prefs.DisableSendingViaIPC) + if (!Prefs.DisableSendingViaIPC || OverrideDisable) { hPipe = CreateFile(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); @@ -657,4 +687,137 @@ vector stringsplit(string str, string token) { } } return res; +} +void ReadDeviceConfig() +{ + if (jsonPrefs.empty()) + return; + + //Clear current sessions. + Devices.clear(); + + //Iterate nodes + for (const auto& item : jsonPrefs.items()) + { + json j; + if (item.key() == JSON_PREFS_NODE) + break; + + SESSIONPARAMETERS params; + + params.DeviceId = item.key(); + + if (item.value()["Name"].is_string()) + params.Name = item.value()["Name"].get(); + + if (item.value()["UniqueDeviceKey"].is_string()) + params.UniqueDeviceKey = item.value()["UniqueDeviceKey"].get(); + Devices.push_back(params); + } + return; +} + +vector QueryDisplays() +{ + vector targets; + + //populate targets struct with information about attached displays + EnumDisplayMonitors(NULL, NULL, meproc, (LPARAM)&targets); + + return targets; + + +} +static BOOL CALLBACK meproc(HMONITOR hMonitor, HDC hdc, LPRECT lprcMonitor, LPARAM pData) +{ + if (!pData) + return false; + vector* targets = (vector *) pData; + UINT32 requiredPaths, requiredModes; + vector paths; + vector modes; +// DISPLAYCONFIG_TOPOLOGY_ID currentTopologyId; + MONITORINFOEX mi; + LONG isError = ERROR_INSUFFICIENT_BUFFER; + + ZeroMemory(&mi, sizeof(mi)); + mi.cbSize = sizeof(mi); + GetMonitorInfo(hMonitor, &mi); + // wprintf(L"DisplayDevice: %s\n", mi.szDevice); + + isError = GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &requiredPaths, &requiredModes); + if (isError) + { + targets->clear(); + return false; + } + paths.resize(requiredPaths); + modes.resize(requiredModes); + + isError = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &requiredPaths, paths.data(), &requiredModes, modes.data(), NULL); + if (isError) + { + targets->clear(); + return false; + } + paths.resize(requiredPaths); + modes.resize(requiredModes); + + for (auto& p : paths) + { + DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName; + sourceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME; + sourceName.header.size = sizeof(sourceName); + sourceName.header.adapterId = p.sourceInfo.adapterId; + sourceName.header.id = p.sourceInfo.id; + + DisplayConfigGetDeviceInfo(&sourceName.header); + if (wcscmp(mi.szDevice, sourceName.viewGdiDeviceName) == 0) + { + DISPLAYCONFIG_TARGET_DEVICE_NAME name; + name.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME; + name.header.size = sizeof(name); + name.header.adapterId = p.sourceInfo.adapterId; + name.header.id = p.targetInfo.id; + DisplayConfigGetDeviceInfo(&name.header); + wstring FriendlyName = name.monitorFriendlyDeviceName; + if (FriendlyName.find(L"LG TV") != wstring::npos) + { + DISPLAY_INFO di; + di.monitorinfo = mi; + di.hMonitor = hMonitor; + di.hdcMonitor = hdc; + di.rcMonitor2 = *(LPRECT)lprcMonitor; + di.target = name; + targets->push_back(di); + + } + } + } + return true; + +} +bool CheckDisplayTopology(void) +{ + stringstream s; + s << "-daemon topology "; + vector displays = QueryDisplays(); + if (Devices.size() == 0) + return false; + if (displays.size() > 0) + { + for (auto &disp : displays) + { + for (auto &dev : Devices) + { + if (narrow(disp.target.monitorDevicePath) == dev.UniqueDeviceKey) + { + s << dev.DeviceId << " "; + } + } + } + } + s << "*"; + CommunicateWithService(s.str(),true); + return true; } \ No newline at end of file diff --git a/LGTV Companion User/Daemon.h b/LGTV Companion User/Daemon.h index 1f8f5c6..0e1c6f0 100644 --- a/LGTV Companion User/Daemon.h +++ b/LGTV Companion User/Daemon.h @@ -37,19 +37,21 @@ #define APPNAME_SHORT L"LGTVdaemon" #define APP_PATH L"LGTV Companion" #define APPNAME_FULL L"LGTV Companion Daemon" -#define APP_VERSION L"1.7.0" +#define APP_VERSION L"1.8.0" #define WINDOW_CLASS_UNIQUE L"YOLOx0x0x0181818" #define NOTIFY_NEW_PROCESS 1 #define TIMER_MAIN 18 #define TIMER_IDLE 19 #define TIMER_RDP 20 +#define TIMER_TOPOLOGY 21 #define TIMER_MAIN_DELAY_WHEN_BUSY 2000 #define TIMER_MAIN_DELAY_WHEN_IDLE 100 #define TIMER_RDP_DELAY 10000 #define APP_NEW_VERSION WM_USER+9 +#define USER_DISPLAYCHANGE WM_USER+10 #define JSON_PREFS_NODE "LGTV Companion" #define JSON_VERSION "Version" @@ -57,6 +59,7 @@ #define JSON_AUTOUPDATE "AutoUpdate" #define JSON_IDLEBLANK "BlankWhenIdle" #define JSON_IDLEBLANKDELAY "BlankWhenIdleDelay" +#define JSON_ADHERETOPOLOGY "AdhereDisplayTopology" #define PIPENAME TEXT("\\\\.\\pipe\\LGTVyolo") #define NEWRELEASELINK L"https://github.com/JPersson77/LGTVCompanion/releases" @@ -71,6 +74,7 @@ struct PREFS { int version = 2; bool ToastInitialised = false; bool DisableSendingViaIPC = false; + bool AdhereTopology = false; }; class WinToastHandler : public WinToastLib::IWinToastHandler @@ -88,6 +92,18 @@ class WinToastHandler : public WinToastLib::IWinToastHandler void toastFailed() const override {} private: }; +struct SESSIONPARAMETERS { + std::string DeviceId; + std::string Name; + std::string UniqueDeviceKey; +}; +struct DISPLAY_INFO { + DISPLAYCONFIG_TARGET_DEVICE_NAME target; + HMONITOR hMonitor; + HDC hdcMonitor; + RECT rcMonitor2; + MONITORINFOEX monitorinfo; +}; // Forward declarations of functions included in this code module: LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); @@ -96,6 +112,10 @@ bool ReadConfigFile(); std::wstring widen(std::string); std::string narrow(std::wstring); std::vector stringsplit(std::string, std::string); -void CommunicateWithService(std::string); +void CommunicateWithService(std::string, bool OverrideDisable = false); void VersionCheckThread(HWND); -void Log(std::wstring input); \ No newline at end of file +void Log(std::wstring input); +void ReadDeviceConfig(); +std::vector QueryDisplays(); +static BOOL CALLBACK meproc(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData); +bool CheckDisplayTopology(void); \ No newline at end of file diff --git a/LGTV Companion User/LGTV Companion User.rc b/LGTV Companion User/LGTV Companion User.rc index ff4fe6c..b9425d5 100644 --- a/LGTV Companion User/LGTV Companion User.rc +++ b/LGTV Companion User/LGTV Companion User.rc @@ -25,21 +25,21 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // TEXTINCLUDE // -1 TEXTINCLUDE +1 TEXTINCLUDE BEGIN -"resource.h\0" + "resource.h\0" END -2 TEXTINCLUDE +2 TEXTINCLUDE BEGIN -"#include ""winres.h""\r\n" -"\0" + "#include ""winres.h""\r\n" + "\0" END -3 TEXTINCLUDE +3 TEXTINCLUDE BEGIN -"\r\n" -"\0" + "\r\n" + "\0" END #endif // APSTUDIO_INVOKED @@ -47,6 +47,7 @@ END #endif // English (United States) resources ///////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// // English (United Kingdom) resources @@ -64,13 +65,14 @@ STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSM CAPTION "Dialog" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN -EDITTEXT IDC_EDIT, 7, 7, 295, 134, ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL -EDITTEXT IDC_EDIT2, 7, 155, 88, 14, ES_AUTOHSCROLL -LTEXT "LastInputTick", IDC_STATIC, 7, 146, 48, 8 -EDITTEXT IDC_EDIT3, 118, 155, 88, 14, ES_AUTOHSCROLL -LTEXT "Seconds ago", IDC_STATIC, 118, 147, 48, 8 + EDITTEXT IDC_EDIT,7,7,295,134,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL + EDITTEXT IDC_EDIT2,7,155,88,14,ES_AUTOHSCROLL + LTEXT "LastInputTick",IDC_STATIC,7,146,48,8 + EDITTEXT IDC_EDIT3,118,155,88,14,ES_AUTOHSCROLL + LTEXT "Seconds ago",IDC_STATIC,118,147,48,8 END + ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO @@ -79,17 +81,18 @@ END #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN -IDD_MAIN, DIALOG -BEGIN -LEFTMARGIN, 7 -RIGHTMARGIN, 302 -VERTGUIDE, 118 -TOPMARGIN, 7 -BOTTOMMARGIN, 169 -END + IDD_MAIN, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 302 + VERTGUIDE, 118 + TOPMARGIN, 7 + BOTTOMMARGIN, 169 + END END #endif // APSTUDIO_INVOKED + ///////////////////////////////////////////////////////////////////////////// // // AFX_DIALOG_LAYOUT @@ -97,9 +100,10 @@ END IDD_MAIN AFX_DIALOG_LAYOUT BEGIN -0 + 0 END + ///////////////////////////////////////////////////////////////////////////// // // Icon @@ -109,52 +113,57 @@ END // remains consistent on all systems. IDI_ICON1 ICON "mainicon.ico" + ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO -FILEVERSION 1, 0, 0, 1 -PRODUCTVERSION 1, 0, 0, 1 -FILEFLAGSMASK 0x3fL + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL #ifdef _DEBUG -FILEFLAGS 0x1L + FILEFLAGS 0x1L #else -FILEFLAGS 0x0L + FILEFLAGS 0x0L #endif -FILEOS 0x40004L -FILETYPE 0x1L -FILESUBTYPE 0x0L -BEGIN -BLOCK "StringFileInfo" -BEGIN -BLOCK "080904b0" + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L BEGIN -VALUE "CompanyName", "J Persson" -VALUE "FileDescription", "LGTV Companion desktop user mode daemon" -VALUE "FileVersion", "1.0.0.1" -VALUE "InternalName", "LGTVdaemon.exe" -VALUE "LegalCopyright", "Copyright (C) 2021-2022 Jörgen Persson" -VALUE "OriginalFilename", "LGTVdaemon.exe" -VALUE "ProductName", "LGTV Companion (Daemon)" -VALUE "ProductVersion", "1.0.0.1" -END -END -BLOCK "VarFileInfo" -BEGIN -VALUE "Translation", 0x809, 1200 -END + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904b0" + BEGIN + VALUE "CompanyName", "J Persson" + VALUE "FileDescription", "LGTV Companion desktop user mode daemon" + VALUE "FileVersion", "1.0.0.1" + VALUE "InternalName", "LGTVdaemon.exe" + VALUE "LegalCopyright", "Copyright (C) 2021-2022 Jörgen Persson" + VALUE "OriginalFilename", "LGTVdaemon.exe" + VALUE "ProductName", "LGTV Companion (Daemon)" + VALUE "ProductVersion", "1.0.0.1" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1200 + END END #endif // English (United Kingdom) resources ///////////////////////////////////////////////////////////////////////////// + + #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // + ///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED \ No newline at end of file +#endif // not APSTUDIO_INVOKED + diff --git a/LGTV Companion User/LGTV Companion User.vcxproj b/LGTV Companion User/LGTV Companion User.vcxproj index 1164379..92777e5 100644 --- a/LGTV Companion User/LGTV Companion User.vcxproj +++ b/LGTV Companion User/LGTV Companion User.vcxproj @@ -119,6 +119,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true + MultiThreadedDebug Windows @@ -136,6 +137,7 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true + MultiThreaded Windows diff --git a/LGTV Companion User/resource.h b/LGTV Companion User/resource.h index 40aae8b..cce6195 100644 --- a/LGTV Companion User/resource.h +++ b/LGTV Companion User/resource.h @@ -6,15 +6,17 @@ #define IDI_ICON1 103 #define IDC_EDIT 1001 #define IDC_EDIT2 1002 +#define IDC_BUTTON1 1003 +#define IDC_TEST 1003 #define IDC_EDIT3 1004 // Next default values for new objects -// +// #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 104 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1003 +#define _APS_NEXT_CONTROL_VALUE 1004 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif