nvh=mXDmQrl
zgvC#v#cJ#<57EsKj50Z#^J8#ivG&ywlWS6_Jpec?yx
zxj<(;>ygOTy{SG&Uy}1OnAWGOzVZh80(I0nYXN!m`3vV%3^}*Q)`NLg6Mew0=bA?y
z*gnBizg*Y9cYJY_@nqfC^oix4Qmc+gMvaf#%Wl+G8F*R8j$Df>NMHP`dl6Do;zmXf
zBMwMBvTwC
zx39j>7!rS6{Q6h+KReEwlW$7=HK#o`Z)qBF5hqHnq=@mnn;+b+r$5xQ~!YXt>yn
zzw>PDchx$4fo*6#2|*s8mGem3Ty4g^FRpu;EMH(-9_R;6+stQlgMS;`*!Kpwm&M#S
z)!2z`5*>8z;ozPO>dp2s?lm#@YcS1@5#+)BD<++$T?t@60IfbiU*HAhA^jo~Ren=!kukg)&8SBOE_~-UA>GK&yWsuhIb4Bal23BMSwUQPd=3>6gt
zkl&Mem_kO+1$GfTIbpUK
+
+
+
+ true
+ PerMonitorV2
+
+
+
+
+
+
+
+
+
+
diff --git a/LogonHoursManager/app.rc b/LogonHoursManager/app.rc
new file mode 100644
index 0000000000000000000000000000000000000000..7178f2f1be50f152f3bd360a0046f2a9bb259f05
GIT binary patch
literal 8892
zcmdT}`)}e#5T2ha^?z_3>2#+?Nr2=ol}@b)P=P0;$QZT+2Z2Wr$x_Mrb=l+fc@GB|W^AWW9cJ0o`x;vN_}WA78|@p;jNg#o
zCDh&=xu*TPI*zo9(vX(4{%f*_mMWfoe)6z-mviU$
zKn|goX&rZ=rF*%9{3B?GdT2xHbNp8zbqR7(ANy#}<2P-QSsQdQ1NGlU?^%tK<|(xI
z2^7njb{hc$14YD0{s653Z0(j?QyFexwQe-tW~24ft#|}U$|^%W)q=Cg`KTD|MbdKa
zpEG#M8)rcc__GtTon1^MI!-%}dNx%p-%S
z?+7CUjZ@5XjF|y?KHwsPt`#Y_%1xl}Nxm$`-k}d8+7Kg+?;+mF2_rc9;TTfw;bLC=
z8hyRP-J&u%t^f;+!VUCUbX9;hX1YcF{CgP5v=PY=XI9ti>c%cdfO&UKwK|@`1~phq
zXs{Of73JH*^C9$G*HNyM1~k}!k5J#Cyn#pG!akp)s>6GwkM*xUOGPtrO)2ez)?c7C
z0wsFsGM7uitWKKb-p4aeSRVG4X$g+NeGkYr>w2%{C3piI{sz>J6}=n4=*E*}aS4iA
zd7Wg+5KBWDUmFUG@N`zW#EVtI_qe+hE)jK6QcRXKJ5+(gCUn~d@|uXvth&;_kV3lM
zLiuH`EoSvUAA?2kQ3BQ~5mt-HCzH4fkyYm*`Q>JO-IyrD=NaSgQGKK#p{z*YdW2rV
z`#BK6xKEuQYrbd8mRiF8bMhg2e~+4;RJrQ8K!4T-WxR2nvyZj|P^jb1y2HQJ&{kIJ
z2Z}pJtK|0s%zchF(z(FTzMU!6WNaZtYb}9V1G8|=#q1M*F$x|J$?0_85M$%0QdK=M
zGahNAVLq-we|`M8z8pkRES76m^%9~NIc*{D)Bl)J%lQ8iVKk||EyUrRYAxND7G+T)
zy9o`~z&W!=ti^S_n{U$|^k~vr$86h=|9QNv!)jZ~fk$I{m#x{nW%3@vwnWf8&CsJy
zRY$Beth&e{MsKMO(mC4(CozAZxC9;^P}Oj?{{?no
z&GQ!VkyS9|&r4w;XL)(A{5fYy4!EX0&|J;RcTfF?G1Tjy5YL|;XW%m>&0*Gc*n?Ks
zQ7181dn}Peo8bZql)Q=tzM6wDf+p$
za;CD)dUlN2AmPv4Q+mEfZ^L%Wc=ckm6r=k7>l9}4Kq~FXs7o})s7a!cHDfvs&0|8K
zHLm~68@Yz#`mhSBdD+FaXcpG@wtMB7!u`?i?&WbmTko;LSO@>~_7D2we?c`^g6}Y6
zFsjkt&7#~dXm
z9*Lp?F2){4okB{KA&0BE>PoJ-oJ+>Qeb~2xI;D<(X2WBZ%6qdX_vgAx?J07vgF2;e
zkSgcMo+~SlTfC0f9A;-mH|7(Wcu{*)J^ZHVnVJ@Dmy?h4x
zYg2xO%^Z8w2m7aMGS+EwN872{zQj}Z&q^E;ja;Jgy~N68a^EFXJ5Qf;g{Y3xPfSA4
z$fCoYL_0^x?(>|pm29fhCv|D(Ez68fJA=s{KmXKX-nmQ`%`B`Gz7Z?S&hs)61a&jt{Ll;$%`{^ABQW`xF%%AuH(n5w3!;GvN7>8XIZO_7FyVU%SK+u
n&}vHP-1+^vr}~Uh^H23%kE^K
+
+
+
+
\ No newline at end of file
diff --git a/LogonHoursManager/resource.h b/LogonHoursManager/resource.h
new file mode 100644
index 0000000..c6cac94
--- /dev/null
+++ b/LogonHoursManager/resource.h
@@ -0,0 +1,28 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by app.rc
+//
+#define IDD_MAIN 102
+#define IDS_APP_TITLE 103
+#define IDD_ABOUTBOX 103
+#define IDM_ABOUT 104
+#define IDS_WINDOW_CLASS 104
+#define IDM_EXIT 105
+#define IDI_APP 107
+#define IDC_ACCELERATORS 108
+#define IDM_APP 109
+#define IDR_MAINFRAME 128
+#define IDC_COMBO_USER 1000
+#define IDC_GROUP_HOURS 1002
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 130
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1004
+#define _APS_NEXT_SYMED_VALUE 110
+#endif
+#endif
diff --git a/LogonHoursManager/stdafx.cpp b/LogonHoursManager/stdafx.cpp
new file mode 100644
index 0000000..6acde0d
--- /dev/null
+++ b/LogonHoursManager/stdafx.cpp
@@ -0,0 +1,3 @@
+#include "stdafx.h"
+
+// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
diff --git a/LogonHoursManager/stdafx.h b/LogonHoursManager/stdafx.h
new file mode 100644
index 0000000..8c6ad1f
--- /dev/null
+++ b/LogonHoursManager/stdafx.h
@@ -0,0 +1,40 @@
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef STDAFX_H_LogonHoursManager_
+#define STDAFX_H_LogonHoursManager_
+
+#include "targetver.h"
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+#include
+
+#include // NetUserGetInfo(), etc.
+
+// C RunTime Header Files
+#include
+#include
+#include
+#include
+
+// STL
+#include
+
+// ATL
+#include
+
+// WTL
+#include
+extern CAppModule _Module;
+#include // MSG_WM_INITDIALOG, etc.
+#include // CToolTipCtrl
+// #define _ATL_USE_DDX_FLOAT
+#include
+#include // CUpdateUI
+#include
+
+#include
+
+#endif
diff --git a/LogonHoursManager/targetver.h b/LogonHoursManager/targetver.h
new file mode 100644
index 0000000..5a9c7ff
--- /dev/null
+++ b/LogonHoursManager/targetver.h
@@ -0,0 +1,6 @@
+#pragma once
+
+// Including SDKDDKVer.h defines the highest available Windows platform.
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+#include
diff --git a/LogonHoursService/LogonHoursService.vcxproj b/LogonHoursService/LogonHoursService.vcxproj
index 0cd1db4..eb98f3e 100644
--- a/LogonHoursService/LogonHoursService.vcxproj
+++ b/LogonHoursService/LogonHoursService.vcxproj
@@ -30,20 +30,20 @@
-
-
+
+
-
+
<_ProjectFileVersion>15.0.28307.799
-
+
true
-
+
false
@@ -77,8 +77,7 @@
- Create
- Create
+ Create
diff --git a/LogonHoursService/WorkerThread.cpp b/LogonHoursService/WorkerThread.cpp
index e989540..6b7bd20 100644
--- a/LogonHoursService/WorkerThread.cpp
+++ b/LogonHoursService/WorkerThread.cpp
@@ -1,5 +1,7 @@
#include "stdafx.h"
+#include
+
#include "config.h"
#include "Logger.h"
#include "WorkerThread.h"
@@ -28,98 +30,6 @@ LPSTR W2A(LPCWSTR lpwszStrIn)
WorkerData g_WorkerData;
-enum EDayOfWeek
-{
- Sun, Mon, Tue, Wed, Thu, Fri, Sat,
- FIRST = Sun,
- LAST = Sat,
-};
-EDayOfWeek& operator ++(EDayOfWeek& day)
-{
- if (day < EDayOfWeek::LAST)
- {
- int value = static_cast(day);
- day = static_cast(++value);
- return day;
- }
- LOG_ERROR(__func__) << "Cannot increment " << int(day);
- return day;
-}
-
-class LogonHours
-{
-public:
- LogonHours(PBYTE usri2_logon_hours)
- {
- Init(usri2_logon_hours);
- }
- void Init(PBYTE usri2_logon_hours)
- {
- m_all = true;
- int day = Sun;
- int hour = 0; // 0:00
- for (int p = 0; p < 21; ++p)
- {
- const BYTE chunk = usri2_logon_hours[p];
- BYTE mask = 0b00000001;
- for (int bit = 0; bit < 8; ++bit)
- {
- m_data[day][hour] = (chunk & mask) != 0;
- if (!m_data[day][hour])
- m_all = false;
- ++hour;
- mask <<= 1;
- if (hour >= 24)
- {
- ++day;
- hour = 0;
- }
- }
- }
- }
-
- bool All() const { return m_all; }
- bool Allowed(EDayOfWeek day, WORD hour) const
- {
- if (Sun <= day && day <= Sat && 0 <= hour && hour <= 23)
- return m_data[day][hour];
- return false;
- }
- // @return seconds left (for the given time) until the allowed logon period expires, or -1 if no restrictions are set
- // @note 0 (zero) is returned if logon isn't allowed during given time
- long SecondsLeft(EDayOfWeek day, WORD hour, WORD minute, WORD second) const
- {
- if (All())
- return -1;
- if (!Allowed(day, hour))
- return 0;
- long left = (60 - second - 1) + 60 * (60 - minute - 1); // the rest of current hour is allowed
- WORD hour_start = hour + 1; // for the current day - start with the next hour
- EDayOfWeek d = day;
- for (int i = 0; i < 7; ++i) // we'll check all week days starting from the current one
- {
- for (WORD h = hour_start; h < 24; ++h) // check hours until end of day
- {
- if (Allowed(day, h))
- left += 3600;
- else
- return left;
- }
- hour_start = 0; // for the rest of days
- // next day
- if (d == EDayOfWeek::LAST)
- d = EDayOfWeek::FIRST;
- else
- ++d;
- }
- return left;
- }
-
-private:
- bool m_all; // true if no logon restrictions
- bool m_data[7][24];
-};
-
void seconds2time(long seconds, long* days, WORD* hours, WORD* mins, WORD* secs)
{
if (days)
@@ -199,15 +109,9 @@ DWORD WINAPI WorkerThread(LPVOID lpData)
{
const auto& wusername = session.user;
- LPBYTE bufptr;
- // Refer to https://docs.microsoft.com/en-us/windows/win32/api/lmaccess/nf-lmaccess-netusergetinfo
- const NET_API_STATUS result = NetUserGetInfo(NULL, wusername.c_str(), 2, &bufptr);
- if (result == NERR_Success)
+ LogonHours hours;
+ if (hours.InitFrom(wusername.c_str()))
{
- const USER_INFO_2* const userinfo2 = reinterpret_cast(bufptr);
- const LogonHours hours(userinfo2->usri2_logon_hours);
- NetApiBufferFree(bufptr);
-
if (!hours.All())
{
const std::unique_ptr username(W2A(wusername.c_str()));
diff --git a/_props/Cxx.props b/_props/Cxx.props
index b0b1095..e814c35 100644
--- a/_props/Cxx.props
+++ b/_props/Cxx.props
@@ -6,6 +6,13 @@
Unicode
+
+
+
+ $(MSBuildThisFileDirectory)..
+
+
+
EnableFastChecks
From 06316e8131b3361dd3a09554e8d1921d7a52a4f6 Mon Sep 17 00:00:00 2001
From: Anton-V-K <20116984+Anton-V-K@users.noreply.github.com>
Date: Wed, 3 May 2023 14:32:30 +0300
Subject: [PATCH 2/3] actions upgrade
---
.github/workflows/msbuild.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/msbuild.yml b/.github/workflows/msbuild.yml
index 29b6ace..6a33d3d 100644
--- a/.github/workflows/msbuild.yml
+++ b/.github/workflows/msbuild.yml
@@ -16,10 +16,10 @@ jobs:
runs-on: windows-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Add MSBuild to PATH
- uses: microsoft/setup-msbuild@v1.0.2
+ uses: microsoft/setup-msbuild@v1.1
- name: Restore NuGet packages
working-directory: ${{env.GITHUB_WORKSPACE}}
From e8ce988bb49397a7d22a6f3d91d27f4bc3478bdd Mon Sep 17 00:00:00 2001
From: Anton-V-K <20116984+Anton-V-K@users.noreply.github.com>
Date: Wed, 10 May 2023 02:06:48 +0300
Subject: [PATCH 3/3] v1.1.0-alpha
---
.gitignore | 2 +-
Common/Common.vcxitems | 4 +
Common/Logger.cpp | 105 +++++++++++
Common/Logger.h | 2 +
Common/LogonHours.cpp | 3 +
Common/REPEAT.h | 177 ++++++++++++++++++
{LogonHoursService => Common}/version.h | 6 +-
LogonHoursManager/LogonHoursManager.vcxproj | 7 +-
.../LogonHoursManager.vcxproj.filters | 3 +
LogonHoursManager/MainDialog.cpp | 130 ++++++++++---
LogonHoursManager/MainDialog.h | 18 +-
LogonHoursManager/MainModel.cpp | 29 +++
LogonHoursManager/MainModel.h | 2 +
LogonHoursManager/UIEx.h | 9 +
LogonHoursManager/WinDataExchangeEx.h | 2 +-
LogonHoursManager/WinMain.cpp | 2 +
LogonHoursManager/stdafx.h | 7 +
LogonHoursService/LogonHoursService.rc | 4 +-
LogonHoursService/LogonHoursService.vcxproj | 6 -
LogonHoursService/main.cpp | 90 +--------
README.md | 41 +++-
_props/Cxx.props | 6 +
_props/Linker.props | 21 ++-
_props/RC.props | 10 +
_props/TARGET_EXE.props | 1 +
25 files changed, 539 insertions(+), 148 deletions(-)
create mode 100644 Common/Logger.cpp
create mode 100644 Common/REPEAT.h
rename {LogonHoursService => Common}/version.h (62%)
create mode 100644 LogonHoursManager/UIEx.h
create mode 100644 _props/RC.props
diff --git a/.gitignore b/.gitignore
index d456880..d9a1d01 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,5 +38,5 @@
/_crashes
/_releases
-*.vcxproj.user
*.aps
+*.vcxproj.user
diff --git a/Common/Common.vcxitems b/Common/Common.vcxitems
index 51ab425..72701ee 100644
--- a/Common/Common.vcxitems
+++ b/Common/Common.vcxitems
@@ -14,10 +14,14 @@
+
+
+
+
\ No newline at end of file
diff --git a/Common/Logger.cpp b/Common/Logger.cpp
new file mode 100644
index 0000000..aaa3067
--- /dev/null
+++ b/Common/Logger.cpp
@@ -0,0 +1,105 @@
+#include "stdafx.h"
+#include "Logger.h"
+
+#include
+#include
+#include
+#include
+
+#include "version.h"
+
+#pragma comment(lib, "ws2_32.lib") // Needed for log4cpp if PropertyConfigurator is used
+
+void LogMain(const char* appname)
+{
+ log4cpp::Category& root = log4cpp::Category::getRoot();
+
+ ////////////////////////////////////////
+ // Configure log4cpp
+ ////////////////////////////////////////
+ char config_path[_MAX_PATH] = { 0 };
+ GetModuleFileNameA(NULL, config_path, _countof(config_path));
+ strcat_s(config_path, ".log4cpp");
+ try
+ {
+ log4cpp::PropertyConfigurator::configure(config_path);
+ }
+ catch (const log4cpp::ConfigureFailure& /*ex*/)
+ {
+ config_path[0] = 0;
+
+ // Default configuration for log4cpp
+#ifdef _DEBUG
+ root.setPriority(log4cpp::Priority::DEBUG);
+#else
+ root.setPriority(log4cpp::Priority::INFO);
+#endif
+
+ }
+
+ const log4cpp::AppenderSet& set = root.getAllAppenders();
+ if (set.empty()) // if no appenders are specified in the config file ...
+ {
+ char log_path_format[MAX_PATH];
+ ExpandEnvironmentStringsA("%TEMP%\\%s.log", log_path_format, _countof(log_path_format));
+
+ char log_path[MAX_PATH];
+ if (appname)
+ sprintf_s(log_path, log_path_format, appname);
+ else
+ {
+ char module_path[_MAX_PATH] = { 0 };
+ GetModuleFileNameA(NULL, module_path, _countof(module_path));
+
+ char filename[MAX_PATH] = { 0 };
+ _splitpath_s(module_path, NULL, 0, NULL, 0, filename, _countof(filename), NULL, 0);
+ sprintf_s(log_path, log_path_format, filename);
+ }
+
+#if 1
+ if (log4cpp::Appender* const appender = new log4cpp::DailyRollingFileAppender("logfile", log_path, 14))
+#else
+ if (log4cpp::Appender* const appender = new log4cpp::RollingFileAppender("logfile", log_path, 10*1024*1024, 10))
+//#else
+ if (log4cpp::Appender* const appender = new log4cpp::FileAppender("logfile", log_path))
+#endif
+ {
+ log4cpp::PatternLayout* const layout = new log4cpp::PatternLayout();
+ // Refer to http://www.cplusplus.com/reference/ctime/strftime/ for format specification
+ layout->setConversionPattern("%d{%Y.%m.%d %H:%M:%S,%l} [%p] [%t] %c: %m%n");
+ appender->setLayout(layout);
+ root.addAppender(appender);
+ }
+ if (log4cpp::Appender* const appender = new log4cpp::Win32DebugAppender("debugger"))
+ {
+ log4cpp::PatternLayout* const layout = new log4cpp::PatternLayout();
+ // Refer to http://www.cplusplus.com/reference/ctime/strftime/ for format specification
+ layout->setConversionPattern("%d{%H:%M:%S,%l} [%p] [%t] %c: %m%n");
+ appender->setLayout(layout);
+ root.addAppender(appender);
+ }
+ }
+
+ LOG_INFO(__func__) << "========================================";
+ LOG_INFO(__func__) << "Log initialized successfully";
+ if (*config_path)
+ LOG_INFO(__func__) << "Loaded " << config_path;
+
+#ifndef _CONSOLE
+ LOG_INFO(__func__) << "Length of command line: " << _tcslen(GetCommandLine());
+#endif
+
+ LOG_INFO(__func__) << "Version: " << VERSION_STRING;
+ LOG_INFO(__func__) << "Build : " << __DATE__ << ' ' << __TIME__;
+#if defined(_MSC_FULL_VER)
+ LOG_INFO(__func__) << "_MSC_FULL_VER: "
+ << _MSC_FULL_VER / 10000000 << '.'
+ << (_MSC_FULL_VER % 10000000) / 100000 << '.'
+ << _MSC_FULL_VER % 100000;
+#elif defined(_MSC_VER)
+ LOG_INFO(__func__) << "_MSC_VER: "
+ << _MSC_VER / 100 << '.'
+ << _MSC_VER % 100;
+#endif
+
+}
diff --git a/Common/Logger.h b/Common/Logger.h
index 6128d78..f57981f 100644
--- a/Common/Logger.h
+++ b/Common/Logger.h
@@ -49,3 +49,5 @@ inline log4cpp::Category& Logger(const void* p = NULL)
{
return log4cpp::Category::getRoot();
}
+
+void LogMain(const char* appname = nullptr);
diff --git a/Common/LogonHours.cpp b/Common/LogonHours.cpp
index 9500c1b..413d027 100644
--- a/Common/LogonHours.cpp
+++ b/Common/LogonHours.cpp
@@ -65,7 +65,10 @@ bool LogonHours::ApplyTo(const wchar_t* username) const
info.usri1020_units_per_week = UNITS_PER_WEEK; // NetUserAdd and NetUserSetInfo functions ignore this member
info.usri1020_logon_hours = usri2_logon_hours;
if (NetUserSetInfo(NULL, username, 1020, reinterpret_cast(&info), &parm_err) != NERR_Success)
+ {
+ LOG_ERROR(__func__) << "NetUserSetInfo() failed with error " << GetLastError();
return false;
+ }
return true;
}
diff --git a/Common/REPEAT.h b/Common/REPEAT.h
new file mode 100644
index 0000000..60cf78a
--- /dev/null
+++ b/Common/REPEAT.h
@@ -0,0 +1,177 @@
+#pragma once
+
+// The approach was taken from https://dev.to/sgf4/repeat-macro-in-c-2hh0
+
+
+#define REPEAT_1(FN, START) FN(START+0)
+#define REPEAT_2(FN, START) REPEAT_1(FN, START) FN(START+1)
+#define REPEAT_3(FN, START) REPEAT_2(FN, START) FN(START+2)
+#define REPEAT_4(FN, START) REPEAT_3(FN, START) FN(START+3)
+#define REPEAT_5(FN, START) REPEAT_4(FN, START) FN(START+4)
+#define REPEAT_6(FN, START) REPEAT_5(FN, START) FN(START+5)
+#define REPEAT_7(FN, START) REPEAT_6(FN, START) FN(START+6)
+#define REPEAT_8(FN, START) REPEAT_7(FN, START) FN(START+7)
+#define REPEAT_9(FN, START) REPEAT_8(FN, START) FN(START+8)
+#define REPEAT_10(FN, START) REPEAT_9(FN, START) FN(START+9)
+#define REPEAT_11(FN, START) REPEAT_10(FN, START) FN(START+10)
+#define REPEAT_12(FN, START) REPEAT_11(FN, START) FN(START+11)
+#define REPEAT_13(FN, START) REPEAT_12(FN, START) FN(START+12)
+#define REPEAT_14(FN, START) REPEAT_13(FN, START) FN(START+13)
+#define REPEAT_15(FN, START) REPEAT_14(FN, START) FN(START+14)
+#define REPEAT_16(FN, START) REPEAT_15(FN, START) FN(START+15)
+#define REPEAT_17(FN, START) REPEAT_16(FN, START) FN(START+16)
+#define REPEAT_18(FN, START) REPEAT_17(FN, START) FN(START+17)
+#define REPEAT_19(FN, START) REPEAT_18(FN, START) FN(START+18)
+#define REPEAT_20(FN, START) REPEAT_19(FN, START) FN(START+19)
+#define REPEAT_21(FN, START) REPEAT_20(FN, START) FN(START+20)
+#define REPEAT_22(FN, START) REPEAT_21(FN, START) FN(START+21)
+#define REPEAT_23(FN, START) REPEAT_22(FN, START) FN(START+22)
+#define REPEAT_24(FN, START) REPEAT_23(FN, START) FN(START+23)
+#define REPEAT_25(FN, START) REPEAT_24(FN, START) FN(START+24)
+#define REPEAT_26(FN, START) REPEAT_25(FN, START) FN(START+25)
+#define REPEAT_27(FN, START) REPEAT_26(FN, START) FN(START+26)
+#define REPEAT_28(FN, START) REPEAT_27(FN, START) FN(START+27)
+#define REPEAT_29(FN, START) REPEAT_28(FN, START) FN(START+28)
+#define REPEAT_30(FN, START) REPEAT_29(FN, START) FN(START+29)
+#define REPEAT_31(FN, START) REPEAT_30(FN, START) FN(START+30)
+#define REPEAT_32(FN, START) REPEAT_31(FN, START) FN(START+31)
+#define REPEAT_33(FN, START) REPEAT_32(FN, START) FN(START+32)
+#define REPEAT_34(FN, START) REPEAT_33(FN, START) FN(START+33)
+#define REPEAT_35(FN, START) REPEAT_34(FN, START) FN(START+34)
+#define REPEAT_36(FN, START) REPEAT_35(FN, START) FN(START+35)
+#define REPEAT_37(FN, START) REPEAT_36(FN, START) FN(START+36)
+#define REPEAT_38(FN, START) REPEAT_37(FN, START) FN(START+37)
+#define REPEAT_39(FN, START) REPEAT_38(FN, START) FN(START+38)
+#define REPEAT_40(FN, START) REPEAT_39(FN, START) FN(START+39)
+#define REPEAT_41(FN, START) REPEAT_40(FN, START) FN(START+40)
+#define REPEAT_42(FN, START) REPEAT_41(FN, START) FN(START+41)
+#define REPEAT_43(FN, START) REPEAT_42(FN, START) FN(START+42)
+#define REPEAT_44(FN, START) REPEAT_43(FN, START) FN(START+43)
+#define REPEAT_45(FN, START) REPEAT_44(FN, START) FN(START+44)
+#define REPEAT_46(FN, START) REPEAT_45(FN, START) FN(START+45)
+#define REPEAT_47(FN, START) REPEAT_46(FN, START) FN(START+46)
+#define REPEAT_48(FN, START) REPEAT_47(FN, START) FN(START+47)
+#define REPEAT_49(FN, START) REPEAT_48(FN, START) FN(START+48)
+#define REPEAT_50(FN, START) REPEAT_49(FN, START) FN(START+49)
+#define REPEAT_51(FN, START) REPEAT_50(FN, START) FN(START+50)
+#define REPEAT_52(FN, START) REPEAT_51(FN, START) FN(START+51)
+#define REPEAT_53(FN, START) REPEAT_52(FN, START) FN(START+52)
+#define REPEAT_54(FN, START) REPEAT_53(FN, START) FN(START+53)
+#define REPEAT_55(FN, START) REPEAT_54(FN, START) FN(START+54)
+#define REPEAT_56(FN, START) REPEAT_55(FN, START) FN(START+55)
+#define REPEAT_57(FN, START) REPEAT_56(FN, START) FN(START+56)
+#define REPEAT_58(FN, START) REPEAT_57(FN, START) FN(START+57)
+#define REPEAT_59(FN, START) REPEAT_58(FN, START) FN(START+58)
+#define REPEAT_60(FN, START) REPEAT_59(FN, START) FN(START+59)
+#define REPEAT_61(FN, START) REPEAT_60(FN, START) FN(START+60)
+#define REPEAT_62(FN, START) REPEAT_61(FN, START) FN(START+61)
+#define REPEAT_63(FN, START) REPEAT_62(FN, START) FN(START+62)
+#define REPEAT_64(FN, START) REPEAT_63(FN, START) FN(START+63)
+#define REPEAT_65(FN, START) REPEAT_64(FN, START) FN(START+64)
+#define REPEAT_66(FN, START) REPEAT_65(FN, START) FN(START+65)
+#define REPEAT_67(FN, START) REPEAT_66(FN, START) FN(START+66)
+#define REPEAT_68(FN, START) REPEAT_67(FN, START) FN(START+67)
+#define REPEAT_69(FN, START) REPEAT_68(FN, START) FN(START+68)
+#define REPEAT_70(FN, START) REPEAT_69(FN, START) FN(START+69)
+#define REPEAT_71(FN, START) REPEAT_70(FN, START) FN(START+70)
+#define REPEAT_72(FN, START) REPEAT_71(FN, START) FN(START+71)
+#define REPEAT_73(FN, START) REPEAT_72(FN, START) FN(START+72)
+#define REPEAT_74(FN, START) REPEAT_73(FN, START) FN(START+73)
+#define REPEAT_75(FN, START) REPEAT_74(FN, START) FN(START+74)
+#define REPEAT_76(FN, START) REPEAT_75(FN, START) FN(START+75)
+#define REPEAT_77(FN, START) REPEAT_76(FN, START) FN(START+76)
+#define REPEAT_78(FN, START) REPEAT_77(FN, START) FN(START+77)
+#define REPEAT_79(FN, START) REPEAT_78(FN, START) FN(START+78)
+#define REPEAT_80(FN, START) REPEAT_79(FN, START) FN(START+79)
+#define REPEAT_81(FN, START) REPEAT_80(FN, START) FN(START+80)
+#define REPEAT_82(FN, START) REPEAT_81(FN, START) FN(START+81)
+#define REPEAT_83(FN, START) REPEAT_82(FN, START) FN(START+82)
+#define REPEAT_84(FN, START) REPEAT_83(FN, START) FN(START+83)
+#define REPEAT_85(FN, START) REPEAT_84(FN, START) FN(START+84)
+#define REPEAT_86(FN, START) REPEAT_85(FN, START) FN(START+85)
+#define REPEAT_87(FN, START) REPEAT_86(FN, START) FN(START+86)
+#define REPEAT_88(FN, START) REPEAT_87(FN, START) FN(START+87)
+#define REPEAT_89(FN, START) REPEAT_88(FN, START) FN(START+88)
+#define REPEAT_90(FN, START) REPEAT_89(FN, START) FN(START+89)
+#define REPEAT_91(FN, START) REPEAT_90(FN, START) FN(START+90)
+#define REPEAT_92(FN, START) REPEAT_91(FN, START) FN(START+91)
+#define REPEAT_93(FN, START) REPEAT_92(FN, START) FN(START+92)
+#define REPEAT_94(FN, START) REPEAT_93(FN, START) FN(START+93)
+#define REPEAT_95(FN, START) REPEAT_94(FN, START) FN(START+94)
+#define REPEAT_96(FN, START) REPEAT_95(FN, START) FN(START+95)
+#define REPEAT_97(FN, START) REPEAT_96(FN, START) FN(START+96)
+#define REPEAT_98(FN, START) REPEAT_97(FN, START) FN(START+97)
+#define REPEAT_99(FN, START) REPEAT_98(FN, START) FN(START+98)
+#define REPEAT_100(FN, START) REPEAT_99(FN, START) FN(START+99)
+#define REPEAT_101(FN, START) REPEAT_100(FN, START) FN(START+100)
+#define REPEAT_102(FN, START) REPEAT_101(FN, START) FN(START+101)
+#define REPEAT_103(FN, START) REPEAT_102(FN, START) FN(START+102)
+#define REPEAT_104(FN, START) REPEAT_103(FN, START) FN(START+103)
+#define REPEAT_105(FN, START) REPEAT_104(FN, START) FN(START+104)
+#define REPEAT_106(FN, START) REPEAT_105(FN, START) FN(START+105)
+#define REPEAT_107(FN, START) REPEAT_106(FN, START) FN(START+106)
+#define REPEAT_108(FN, START) REPEAT_107(FN, START) FN(START+107)
+#define REPEAT_109(FN, START) REPEAT_108(FN, START) FN(START+108)
+#define REPEAT_110(FN, START) REPEAT_109(FN, START) FN(START+109)
+#define REPEAT_111(FN, START) REPEAT_110(FN, START) FN(START+110)
+#define REPEAT_112(FN, START) REPEAT_111(FN, START) FN(START+111)
+#define REPEAT_113(FN, START) REPEAT_112(FN, START) FN(START+112)
+#define REPEAT_114(FN, START) REPEAT_113(FN, START) FN(START+113)
+#define REPEAT_115(FN, START) REPEAT_114(FN, START) FN(START+114)
+#define REPEAT_116(FN, START) REPEAT_115(FN, START) FN(START+115)
+#define REPEAT_117(FN, START) REPEAT_116(FN, START) FN(START+116)
+#define REPEAT_118(FN, START) REPEAT_117(FN, START) FN(START+117)
+#define REPEAT_119(FN, START) REPEAT_118(FN, START) FN(START+118)
+#define REPEAT_120(FN, START) REPEAT_119(FN, START) FN(START+119)
+#define REPEAT_121(FN, START) REPEAT_120(FN, START) FN(START+120)
+#define REPEAT_122(FN, START) REPEAT_121(FN, START) FN(START+121)
+#define REPEAT_123(FN, START) REPEAT_122(FN, START) FN(START+122)
+#define REPEAT_124(FN, START) REPEAT_123(FN, START) FN(START+123)
+#define REPEAT_125(FN, START) REPEAT_124(FN, START) FN(START+124)
+#define REPEAT_126(FN, START) REPEAT_125(FN, START) FN(START+125)
+#define REPEAT_127(FN, START) REPEAT_126(FN, START) FN(START+126)
+#define REPEAT_128(FN, START) REPEAT_127(FN, START) FN(START+127)
+#define REPEAT_129(FN, START) REPEAT_128(FN, START) FN(START+128)
+#define REPEAT_130(FN, START) REPEAT_129(FN, START) FN(START+129)
+#define REPEAT_131(FN, START) REPEAT_130(FN, START) FN(START+130)
+#define REPEAT_132(FN, START) REPEAT_131(FN, START) FN(START+131)
+#define REPEAT_133(FN, START) REPEAT_132(FN, START) FN(START+132)
+#define REPEAT_134(FN, START) REPEAT_133(FN, START) FN(START+133)
+#define REPEAT_135(FN, START) REPEAT_134(FN, START) FN(START+134)
+#define REPEAT_136(FN, START) REPEAT_135(FN, START) FN(START+135)
+#define REPEAT_137(FN, START) REPEAT_136(FN, START) FN(START+136)
+#define REPEAT_138(FN, START) REPEAT_137(FN, START) FN(START+137)
+#define REPEAT_139(FN, START) REPEAT_138(FN, START) FN(START+138)
+#define REPEAT_140(FN, START) REPEAT_139(FN, START) FN(START+139)
+#define REPEAT_141(FN, START) REPEAT_140(FN, START) FN(START+140)
+#define REPEAT_142(FN, START) REPEAT_141(FN, START) FN(START+141)
+#define REPEAT_143(FN, START) REPEAT_142(FN, START) FN(START+142)
+#define REPEAT_144(FN, START) REPEAT_143(FN, START) FN(START+143)
+#define REPEAT_145(FN, START) REPEAT_144(FN, START) FN(START+144)
+#define REPEAT_146(FN, START) REPEAT_145(FN, START) FN(START+145)
+#define REPEAT_147(FN, START) REPEAT_146(FN, START) FN(START+146)
+#define REPEAT_148(FN, START) REPEAT_147(FN, START) FN(START+147)
+#define REPEAT_149(FN, START) REPEAT_148(FN, START) FN(START+148)
+#define REPEAT_150(FN, START) REPEAT_149(FN, START) FN(START+149)
+#define REPEAT_151(FN, START) REPEAT_150(FN, START) FN(START+150)
+#define REPEAT_152(FN, START) REPEAT_151(FN, START) FN(START+151)
+#define REPEAT_153(FN, START) REPEAT_152(FN, START) FN(START+152)
+#define REPEAT_154(FN, START) REPEAT_153(FN, START) FN(START+153)
+#define REPEAT_155(FN, START) REPEAT_154(FN, START) FN(START+154)
+#define REPEAT_156(FN, START) REPEAT_155(FN, START) FN(START+155)
+#define REPEAT_157(FN, START) REPEAT_156(FN, START) FN(START+156)
+#define REPEAT_158(FN, START) REPEAT_157(FN, START) FN(START+157)
+#define REPEAT_159(FN, START) REPEAT_158(FN, START) FN(START+158)
+#define REPEAT_160(FN, START) REPEAT_159(FN, START) FN(START+159)
+#define REPEAT_161(FN, START) REPEAT_160(FN, START) FN(START+160)
+#define REPEAT_162(FN, START) REPEAT_161(FN, START) FN(START+161)
+#define REPEAT_163(FN, START) REPEAT_162(FN, START) FN(START+162)
+#define REPEAT_164(FN, START) REPEAT_163(FN, START) FN(START+163)
+#define REPEAT_165(FN, START) REPEAT_164(FN, START) FN(START+164)
+#define REPEAT_166(FN, START) REPEAT_165(FN, START) FN(START+165)
+#define REPEAT_167(FN, START) REPEAT_166(FN, START) FN(START+166)
+#define REPEAT_168(FN, START) REPEAT_167(FN, START) FN(START+167)
+
+#define REPEAT_N(FN, N, START) REPEAT_##N(FN, START)
+// #define EVAL(x) #x
+// TODO? #define REPEAT(FN, N1, N2) REPEAT_N(FN, EVAL(N2-N1), N1)
diff --git a/LogonHoursService/version.h b/Common/version.h
similarity index 62%
rename from LogonHoursService/version.h
rename to Common/version.h
index 2d6c3a5..cffd4bd 100644
--- a/LogonHoursService/version.h
+++ b/Common/version.h
@@ -8,9 +8,9 @@
#endif
#define VERSION_MAJOR 1
-#define VERSION_MINOR 0
-#define VERSION_REV 3
+#define VERSION_MINOR 1
+#define VERSION_REV 0
-#define VERSION_STRING "1.0.3 Alpha" VERSION_CONFIG
+#define VERSION_STRING "1.1.0 Alpha" VERSION_CONFIG
#endif
diff --git a/LogonHoursManager/LogonHoursManager.vcxproj b/LogonHoursManager/LogonHoursManager.vcxproj
index cccc939..0473486 100644
--- a/LogonHoursManager/LogonHoursManager.vcxproj
+++ b/LogonHoursManager/LogonHoursManager.vcxproj
@@ -50,12 +50,6 @@
-
- true
-
-
- false
-
Level3
@@ -117,6 +111,7 @@
+
diff --git a/LogonHoursManager/LogonHoursManager.vcxproj.filters b/LogonHoursManager/LogonHoursManager.vcxproj.filters
index 74e1671..1bb7466 100644
--- a/LogonHoursManager/LogonHoursManager.vcxproj.filters
+++ b/LogonHoursManager/LogonHoursManager.vcxproj.filters
@@ -33,6 +33,9 @@
Header Files
+
+ Header Files
+
diff --git a/LogonHoursManager/MainDialog.cpp b/LogonHoursManager/MainDialog.cpp
index 6505b48..fb8106a 100644
--- a/LogonHoursManager/MainDialog.cpp
+++ b/LogonHoursManager/MainDialog.cpp
@@ -14,6 +14,23 @@ CMainDialog::~CMainDialog()
LRESULT CMainDialog::OnClose(UINT, int, HWND)
{
+ if (m_week_modified)
+ {
+ TCHAR message[1024];
+ _stprintf_s(message, _T("Allowed Logon Hours for the user '%s' were modified.\nDo you want to apply the changes?"), m_userName);
+ const auto answer = MessageBox(message, _T("Confirm the changes"), MB_ICONQUESTION | MB_YESNOCANCEL);
+ switch (answer)
+ {
+ case IDCANCEL:
+ return 0;
+ case IDYES:
+ ApplyChanges(true);
+ break;
+ case IDNO:
+ // discard changes
+ break;
+ }
+ }
EndDialog(0);
return 0;
}
@@ -27,6 +44,12 @@ LRESULT CMainDialog::OnInitDialog(HWND, LPARAM)
HICON hIcon = ::LoadIcon(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDI_APP));
SetIcon(hIcon);
+ if (!m_model.isElevated())
+ {
+ SetDlgItemText(IDOK, _T("Restart"));
+ SendDlgItemMessage(IDOK, BCM_SETSHIELD, 0, TRUE);
+ }
+
m_ctrlToolTip.Create(m_hWnd); // , rcDefault, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, WS_EX_TOPMOST);
ATLASSERT(m_ctrlToolTip.IsWindow());
@@ -111,47 +134,109 @@ LRESULT CMainDialog::OnInitDialog(HWND, LPARAM)
FetchData();
- DoDataExchange(DDX_LOAD);
-
UIAddChildWindowContainer(m_hWnd);
UpdateUI(true);
return 0;
}
-/*DEL?
+
+LRESULT CMainDialog::OnOK(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& bHandled)
+{
+ if (m_model.isElevated())
+ {
+ ApplyChanges(false);
+ }
+ else
+ {
+ // TODO move to another class?
+
+ TCHAR filepath[MAX_PATH];
+ GetModuleFileName(NULL, filepath, sizeof(filepath));
+
+ TCHAR curdir[MAX_PATH];
+ GetCurrentDirectory(_countof(curdir), curdir);
+
+ SHELLEXECUTEINFO shex = { 0 };
+
+ shex.cbSize = sizeof(shex);
+ shex.fMask = SEE_MASK_UNICODE | SEE_MASK_NOZONECHECKS | SEE_MASK_FLAG_NO_UI | SEE_MASK_NOASYNC;
+ shex.lpVerb = L"runas";
+ shex.nShow = SW_SHOW;
+ shex.lpFile = filepath;
+ // TODO pass currently selected user
+ shex.lpParameters = GetCommandLine();
+ shex.lpDirectory = curdir;
+
+ if (ShellExecuteEx(&shex))
+ {
+ EndDialog(0);
+ }
+ else
+ LOG_ERROR(__func__) << "ShellExecuteEx() failed with error " << GetLastError();
+ }
+ // bHandled = TRUE;
+ return 0;
+}
+
LRESULT CMainDialog::OnHourChanged(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
{
if (wNotifyCode == BN_CLICKED)
{
- // UpdateData();
- // DisplayGUID();
- if (IDC_HOURS_FIRST <= wID && wID <= IDC_HOURS_LAST)
+ if (m_model.isElevated())
{
- const auto span = wID - IDC_HOURS_FIRST;
- const auto day = span / 24;
- const auto hour = span % 24;
- const auto check = Button_GetCheck(hWndCtl);
- m_model.getHours().Allow(EDayOfWeek(day), hour, check == BST_CHECKED);
- // TODO m_model.getHours().ApplyTo(m_model.getUser());
+ m_week_modified = true;
+ UpdateUI();
+ }
+ else
+ {
+ bHandled = FALSE;
+
}
}
return 0;
}
-*/
+
LRESULT CMainDialog::OnUserChanged(UINT, int, HWND)
{
+ if (m_week_modified)
+ {
+ TCHAR message[1024];
+ _stprintf_s(message, _T("Allowed Logon Hours for the user '%s' were modified.\nDo you want to apply the changes?"), m_userName);
+ if (MessageBox(message, _T("Confirm the changes"), MB_ICONQUESTION | MB_YESNO) == IDYES)
+ {
+ ApplyChanges(true);
+ }
+ }
UpdateUI();
m_model.selectUser(m_userName);
FetchData();
- DoDataExchange(DDX_LOAD);
+ UpdateUI(true);
return 0;
}
+void CMainDialog::ApplyChanges(bool prev_user)
+{
+ const std::wstring userName = prev_user ? m_userName : L""; // m_userName will be changed during DDX
+ DoDataExchange(DDX_SAVE);
+ m_model.getHours().Set(m_week, false);
+ if (m_model.getHours().ApplyTo(userName.empty() ? m_userName : userName.c_str()))
+ {
+ m_week_modified = false;
+ }
+ else
+ {
+ MessageBox(_T("Cannot apply these changes!"), _T("Error"), MB_ICONERROR | MB_OK);
+ }
+ UpdateUI(false);
+}
+
void CMainDialog::FetchData()
{
wcscpy_s(m_userName, m_model.getUser());
m_users = m_model.getUsers();
m_model.getHours().Get(m_week, false);
+ m_week_modified = false;
+ DoDataExchange(DDX_LOAD);
}
void CMainDialog::UpdateUI(bool saved)
@@ -159,26 +244,15 @@ void CMainDialog::UpdateUI(bool saved)
const auto isValid = saved || DoDataExchange(DDX_SAVE);
for (UINT id = IDC_HOURS_FIRST; id <= IDC_HOURS_LAST; ++id)
- UIEnable(id, isValid && m_userName[0] != 0);
+ UIEnable(id, isValid && m_userName[0] != 0 && m_model.isElevated());
if (isValid)
{
-
-/*DEL
- UIEnable(IDC_EXP, TRUE);
- UIEnable(IDC_LN, m_number > 0);
- UIEnable(IDC_SQRT, m_number >= 0);
- UIEnable(IDC_FACT, m_number <= 100 && m_number > 0 && ((double)(unsigned long)m_number == m_number));
-*/
+ UIEnable(IDOK, !m_model.isElevated() || m_week_modified);
}
else
{
-/*DEL
- UIEnable(IDC_EXP, FALSE);
- UIEnable(IDC_LN, FALSE);
- UIEnable(IDC_SQRT, FALSE);
- UIEnable(IDC_FACT, FALSE);
-*/
+ UIEnable(IDOK, FALSE);
}
UIUpdateChildWindows();
diff --git a/LogonHoursManager/MainDialog.h b/LogonHoursManager/MainDialog.h
index 5dd34ab..d77aee3 100644
--- a/LogonHoursManager/MainDialog.h
+++ b/LogonHoursManager/MainDialog.h
@@ -9,6 +9,7 @@
#include
#include "WinDataExchangeEx.h"
+#include "UIEx.h"
#include "resource.h"
@@ -30,7 +31,11 @@ class CMainDialog
TCHAR m_userName[256] = _T("");
std::vector m_users;
+ ///
+ /// Temporary data while the user is editing it
+ ///
WeekHours m_week;
+ bool m_week_modified{ false };
public:
enum EID
@@ -38,13 +43,14 @@ class CMainDialog
IDD = IDD_MAIN,
IDC_HOURS_FIRST = IDC_GROUP_HOURS + 1,
- IDC_HOURS_LAST = IDC_HOURS_FIRST + 7 * 24,
+ IDC_HOURS_LAST = IDC_HOURS_FIRST + 7 * 24 - 1,
IDC_HOURS_COUNT = IDC_HOURS_LAST - IDC_HOURS_FIRST,
};
BEGIN_MSG_MAP(Self)
MSG_WM_INITDIALOG(OnInitDialog)
- // COMMAND_RANGE_HANDLER(IDC_HOURS_FIRST, IDC_HOURS_LAST, OnHourChanged)
+ COMMAND_ID_HANDLER(IDOK, OnOK)
+ COMMAND_RANGE_HANDLER(IDC_HOURS_FIRST, IDC_HOURS_LAST, OnHourChanged)
COMMAND_HANDLER_EX(IDC_COMBO_USER, CBN_SELENDOK, OnUserChanged)
COMMAND_HANDLER_EX(IDCANCEL, BN_CLICKED, OnClose)
END_MSG_MAP()
@@ -59,6 +65,9 @@ class CMainDialog
BEGIN_UPDATE_UI_MAP(Self)
UPDATE_ELEMENT(IDC_COMBO_USER, UPDUI_CHILDWINDOW)
UPDATE_ELEMENT(IDOK, UPDUI_CHILDWINDOW)
+ UPDATE_CHILDWINDOWS(IDC_HOURS_FIRST, IDC_HOURS_LAST, 168) // 7 * 24
+ // TODO? UPDATE_ELEMENT(IDC_HOURS_FIRST, UPDUI_CHILDWINDOW)
+ // TODO? UPDATE_ELEMENT(IDC_HOURS_LAST, UPDUI_CHILDWINDOW)
END_UPDATE_UI_MAP()
CMainDialog(MainModel& model);
@@ -72,10 +81,15 @@ class CMainDialog
LRESULT OnInitDialog(HWND, LPARAM);
private:
+ LRESULT OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
+
LRESULT OnHourChanged(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled);
LRESULT OnUserChanged(UINT, int, HWND);
+private:
+ void ApplyChanges(bool prev_user);
+
void FetchData();
void UpdateUI(bool saved = false);
diff --git a/LogonHoursManager/MainModel.cpp b/LogonHoursManager/MainModel.cpp
index cf0c8bf..3c13f59 100644
--- a/LogonHoursManager/MainModel.cpp
+++ b/LogonHoursManager/MainModel.cpp
@@ -46,6 +46,35 @@ std::vector MainModel::getUsers() const
return users;
}
+bool MainModel::isElevated() const
+{
+ static bool init_ok{ false };
+ static TOKEN_ELEVATION_TYPE type;
+ if (!init_ok)
+ {
+ init_ok = true;
+ HANDLE hProcess;
+ if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hProcess))
+ {
+ DWORD size;
+ if (GetTokenInformation(hProcess, TokenElevationType, &type, sizeof(type), &size))
+ {
+ if (size == sizeof(type))
+ {
+ LOG_DEBUG(__func__) << "GetTokenInformation: TOKEN_ELEVATION_TYPE = " << int(type);
+ }
+ }
+ else
+ LOG_ERROR(__func__) << "GetTokenInformation(..., TokenElevationType, ...) failed with error " << GetLastError();
+ CloseHandle(hProcess);
+ }
+ else
+ LOG_ERROR(__func__) << "OpenProcessToken(GetCurrentProcess(), TOKEN_READ, ...) failed with error " << GetLastError();
+ }
+
+ return type == TokenElevationTypeFull;
+}
+
void MainModel::selectUser(const wchar_t* user)
{
if (user)
diff --git a/LogonHoursManager/MainModel.h b/LogonHoursManager/MainModel.h
index f5b66a1..7bb4a78 100644
--- a/LogonHoursManager/MainModel.h
+++ b/LogonHoursManager/MainModel.h
@@ -14,6 +14,8 @@ class MainModel
const wchar_t* getUser() const;
std::vector getUsers() const;
+ bool isElevated() const;
+
void selectUser(const wchar_t* user);
protected:
diff --git a/LogonHoursManager/UIEx.h b/LogonHoursManager/UIEx.h
new file mode 100644
index 0000000..1ca4a70
--- /dev/null
+++ b/LogonHoursManager/UIEx.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include
+
+#define UPDATE_CHILDWINDOW(nID) \
+ { nID, UPDUI_CHILDWINDOW },
+
+#define UPDATE_CHILDWINDOWS(nStartID, nEndId, count) \
+ REPEAT_N(UPDATE_CHILDWINDOW, count, nStartID)
diff --git a/LogonHoursManager/WinDataExchangeEx.h b/LogonHoursManager/WinDataExchangeEx.h
index e5d77da..9c714bd 100644
--- a/LogonHoursManager/WinDataExchangeEx.h
+++ b/LogonHoursManager/WinDataExchangeEx.h
@@ -98,7 +98,7 @@ class CWinDataExchangeEx : public CWinDataExchange
};
#define DDX_CHECK_ARRAY(nFirstID, nLastID, arr) \
- static_assert(_countof(arr) == nLastID - nFirstID, "The elements range should match the array's size"); \
+ static_assert(_countof(arr) == nLastID - nFirstID + 1, "The elements range should match the array's size"); \
if (nFirstID <= nCtlID && nCtlID <= nLastID) \
DDX_Check(nCtlID, arr[nCtlID - nFirstID], bSaveAndValidate); \
if (nCtlID == (UINT)-1) \
diff --git a/LogonHoursManager/WinMain.cpp b/LogonHoursManager/WinMain.cpp
index a6a91a0..16d4c31 100644
--- a/LogonHoursManager/WinMain.cpp
+++ b/LogonHoursManager/WinMain.cpp
@@ -11,6 +11,8 @@ CAppModule _Module;
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
+ LogMain();
+
_Module.Init(NULL, hInstance);
MainModel model;
diff --git a/LogonHoursManager/stdafx.h b/LogonHoursManager/stdafx.h
index 8c6ad1f..d55856d 100644
--- a/LogonHoursManager/stdafx.h
+++ b/LogonHoursManager/stdafx.h
@@ -12,6 +12,8 @@
#include
#include // NetUserGetInfo(), etc.
+#include // IsUserAnAdmin(), etc.
+#include
// C RunTime Header Files
#include
@@ -35,6 +37,11 @@ extern CAppModule _Module;
#include // CUpdateUI
#include
+#include
+#include
+#include
+#include
+
#include
#endif
diff --git a/LogonHoursService/LogonHoursService.rc b/LogonHoursService/LogonHoursService.rc
index 4fa8c80..1465378 100644
--- a/LogonHoursService/LogonHoursService.rc
+++ b/LogonHoursService/LogonHoursService.rc
@@ -10,7 +10,7 @@
#include
#include "config.h"
-#include "version.h"
+#include "Common/version.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
@@ -37,7 +37,7 @@ BEGIN
"#include \r\n"
"\r\n"
"#include ""config.h""\r\n"
- "#include ""version.h""\r\n"
+ "#include ""Common/version.h""\r\n"
"\0"
END
diff --git a/LogonHoursService/LogonHoursService.vcxproj b/LogonHoursService/LogonHoursService.vcxproj
index eb98f3e..648d720 100644
--- a/LogonHoursService/LogonHoursService.vcxproj
+++ b/LogonHoursService/LogonHoursService.vcxproj
@@ -40,12 +40,6 @@
<_ProjectFileVersion>15.0.28307.799
-
- true
-
-
- false
-
_CONSOLE;WIN32;_DEBUG;%(PreprocessorDefinitions)
diff --git a/LogonHoursService/main.cpp b/LogonHoursService/main.cpp
index 0fa7aad..f620671 100644
--- a/LogonHoursService/main.cpp
+++ b/LogonHoursService/main.cpp
@@ -6,10 +6,6 @@
#include "ServiceManager.h"
#include "WorkerThread.h"
-#include "version.h"
-
-#pragma comment(lib, "ws2_32.lib") // Needed for log4cpp if PropertyConfigurator is used
-
void Main()
{
LOG_DEBUG(__func__) << "Entry";
@@ -56,91 +52,7 @@ int APIENTRY _tWinMain(HINSTANCE hInstance,
{
OutputDebugString(_T(SERVICE_NAME) _T(": Start\n"));
- log4cpp::Category& root = log4cpp::Category::getRoot();
-
- ////////////////////////////////////////
- // Configigure log4cpp
- ////////////////////////////////////////
- char config_path[_MAX_PATH] = { 0 };
- GetModuleFileNameA(NULL, config_path, _countof(config_path));
- strcat_s(config_path, ".log4cpp");
- try
- {
- log4cpp::PropertyConfigurator::configure(config_path);
- }
- catch (const log4cpp::ConfigureFailure& /*ex*/)
- {
- config_path[0] = 0;
-/*
-#ifdef _CONSOLE
- std::cerr
- << ex.what()
- << " [log4cpp::ConfigureFailure catched] while reading "
- << file_log4cpp_init
- << std::endl;
-#endif
-*/
-
- // Default configuration for log4cpp
-#ifdef _DEBUG
- root.setPriority(log4cpp::Priority::DEBUG);
-#else
- root.setPriority(log4cpp::Priority::INFO);
-#endif
-
- }
-
- const log4cpp::AppenderSet& set = root.getAllAppenders();
- if (set.empty()) // if no appenders are specified in the config file ...
- {
- char log_path[MAX_PATH];
- ExpandEnvironmentStringsA("%TEMP%\\" SERVICE_NAME ".log", log_path, _countof(log_path));
-#if 1
- if (log4cpp::Appender* const appender = new log4cpp::DailyRollingFileAppender("logfile", log_path, 14))
-#else
- if (log4cpp::Appender* const appender = new log4cpp::RollingFileAppender("logfile", log_path, 10*1024*1024, 10))
-//#else
- if (log4cpp::Appender* const appender = new log4cpp::FileAppender("logfile", log_path))
-#endif
- {
- log4cpp::PatternLayout* const layout = new log4cpp::PatternLayout();
- // Refer to http://www.cplusplus.com/reference/ctime/strftime/ for format specification
- layout->setConversionPattern("%d{%Y.%m.%d %H:%M:%S,%l} [%p] [%t] %c: %m%n");
- appender->setLayout(layout);
- root.addAppender(appender);
- }
- if (log4cpp::Appender* const appender = new log4cpp::Win32DebugAppender("debugger"))
- {
- log4cpp::PatternLayout* const layout = new log4cpp::PatternLayout();
- // Refer to http://www.cplusplus.com/reference/ctime/strftime/ for format specification
- layout->setConversionPattern("%d{%H:%M:%S,%l} [%p] [%t] %c: %m%n");
- appender->setLayout(layout);
- root.addAppender(appender);
- }
- }
-
- LOG_INFO(__func__) << "========================================";
- LOG_INFO(__func__) << "Log initialized successfully";
- if (*config_path)
- LOG_INFO(__func__) << "Loaded " << config_path;
-
-#ifndef _CONSOLE
- LOG_INFO(__func__) << "Length of command line: " << _tcslen(lpCmdLine);
-#endif
-
- LOG_INFO(__func__) << "Version: " << VERSION_STRING;
- LOG_INFO(__func__) << "Build : " << __DATE__ << ' ' << __TIME__;
-#if defined(_MSC_FULL_VER)
- LOG_INFO(__func__) << "_MSC_FULL_VER: "
- << _MSC_FULL_VER / 10000000 << '.'
- << (_MSC_FULL_VER % 10000000) / 100000 << '.'
- << _MSC_FULL_VER % 100000;
-#elif defined(_MSC_VER)
- LOG_INFO(__func__) << "_MSC_VER: "
- << _MSC_VER / 100 << '.'
- << _MSC_VER % 100;
-#endif
-
+ LogMain(SERVICE_NAME);
#ifdef _CONSOLE
if (argc > 1)
diff --git a/README.md b/README.md
index de9a200..32889b8 100644
--- a/README.md
+++ b/README.md
@@ -1,23 +1,38 @@
[![MSBuild](https://github.com/Anton-V-K/ClassicParentalControl/actions/workflows/msbuild.yml/badge.svg)](actions/workflows/msbuild.yml)
+
# Classic Parental Control (for Windows)
The project provides utility which allows you to establish/maintain Parental Control for Local Accounts in Windows 10.
-- `LogonHoursService` monitors allowed logon hours (which you can set with a command like `net user USERNAME /time:M-F,10-18`) and locks the session once the time is over
+
+- `LogonHoursManager` is a GUI application to easily change to change the allowed logon hours
+- `LogonHoursService` it a service which monitors the allowed logon hours and locks the session once the time is over
+
+The allowed logon hours are the ones you can set with a command like `net user USERNAME /time:M-F,10-18`.
## Compilation
-You need VS2019 with vc142 toolkit to build the solution.
-The project can also be built with older versions of VS after tuning the properties:
+You need VS2019 with v142 toolkit to build the solution.
+
+The project can also be built with other versions of VisualStuido after tuning the properties:
1. Copy `_props\user\_Platform.props.IN` to `_props\user\_Platform.props`
+
2. Adjust `PlatformToolset` to specify available/desired toolset:
- ```
-
- v141
-
- ```
+
+ ```
+
+ v141
+
+ ```
## Installation
+
+### Manager
+
+The application doesn't require any special installation.
+
+### Service
+
1. Copy all binaries from the archive into a directory with read-only access to Everyone, so only Administrators can remove or update them (if needed).
2. Run `LogonHoursService` from command line (with any permissions) for testing purposes, close its console window after ~5 seconds and examine the log in `%TEMP%\LogonHoursService.log`. The log should start with something like this:
`2021.11.28 02:31:03,322 [INFO] [2672] wmain: ========================================`
@@ -50,6 +65,12 @@ After local dumps are enabled, you will be able to find the dump under `%LOCALAP
If you're running the service under `Local System` account, its dumps are generated under `%windir%\System32\config\systemprofile\AppData\Local\CrashDumps` or `%windir%\SysWOW64\config\systemprofile\AppData\Local\CrashDumps` (for 32-bit services on 64-bit system)
+### Missing `clang_rt.asan_dbg_dynamic-i386.dll` in Debug configuration
+
+Both projects have now Address Sanitizer enabled in Debug configuration (refer to `true` in `\_props\Cxx.props`), so when running them not from VisualStudio IDE the system may complain about missing `clang_rt.asan_dbg_dynamic-i386.dll` (for Win32 platform).
+
+It is enough to copy the required DLL from VisualStudio platform toolset directory (something like `C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x86`) to the directory with the executable.
+
## Supported Windows versions
This project is intended to be useful in Windows 10, where you cannot easily establish parental control for Local Accounts.
@@ -61,6 +82,10 @@ Though the built-in classic parental control is available in Windows 7/8.1, you
## History
+### 1.1.0 Alpha (10.05.2023)
+
+- [x] `LogonHoursManager` is available
+
### 1.0.3 Alpha (28.01.2022)
- [x] `DailyRollingFileAppender` is used instead of `RollingFileAppender`
diff --git a/_props/Cxx.props b/_props/Cxx.props
index e814c35..b4d472b 100644
--- a/_props/Cxx.props
+++ b/_props/Cxx.props
@@ -1,12 +1,17 @@
+
Unicode
+
+ true
+
+
$(MSBuildThisFileDirectory)..
@@ -24,6 +29,7 @@
+
ProgramDatabase
diff --git a/_props/Linker.props b/_props/Linker.props
index c6d7acb..129cff4 100644
--- a/_props/Linker.props
+++ b/_props/Linker.props
@@ -1,15 +1,32 @@
-
+
+
Windows
+
+ /ignore:4099 %(AdditionalOptions)
+
+
+
+
+
MachineX86
+
- Windows
MachineX64
+
+
+ false
+
+
+
+ false
+
+
diff --git a/_props/RC.props b/_props/RC.props
new file mode 100644
index 0000000..22169f6
--- /dev/null
+++ b/_props/RC.props
@@ -0,0 +1,10 @@
+
+
+
+
+
+ $(MSBuildThisFileDirectory)..
+
+
+
+
diff --git a/_props/TARGET_EXE.props b/_props/TARGET_EXE.props
index 1ce2aa4..84aeaca 100644
--- a/_props/TARGET_EXE.props
+++ b/_props/TARGET_EXE.props
@@ -4,4 +4,5 @@
+