feat: change mock logic

This commit is contained in:
2026-02-27 09:45:29 +07:00
parent 22d2aa268e
commit 8c50fea618
4 changed files with 34 additions and 69 deletions
+7 -4
View File
@@ -14,7 +14,7 @@ namespace TimeMocker.Hook
[StructLayout(LayoutKind.Sequential)]
public struct MockTimeInfo
{
public long FakeUtcTicks; // DateTime ticks (UTC)
public long DeltaTicks; // Offset to add to DateTime.UtcNow.Ticks (can be negative)
public int Enabled; // 1 = mock active, 0 = passthrough
}
@@ -108,9 +108,12 @@ namespace TimeMocker.Hook
private DateTime GetFakeUtc()
{
var info = ReadMockInfo();
return info.Enabled == 1
? new DateTime(info.FakeUtcTicks, DateTimeKind.Utc)
: DateTime.UtcNow;
if (info.Enabled == 1)
{
// Return real UTC time plus the stored delta offset
return new DateTime(DateTime.UtcNow.Ticks + info.DeltaTicks, DateTimeKind.Utc);
}
return DateTime.UtcNow;
}
private void InstallHooks()
+14 -3
View File
@@ -44,7 +44,7 @@ namespace TimeMocker.UI.Core
try
{
// Write disabled state initially so hook passes through
entry.Shm.Write(new MockTimeInfo { Enabled = 0, FakeUtcTicks = DateTime.UtcNow.Ticks });
entry.Shm.Write(new MockTimeInfo { Enabled = 0, DeltaTicks = 0 });
RemoteHooking.Inject(
process.Id,
@@ -74,9 +74,20 @@ namespace TimeMocker.UI.Core
{
if (!_injected.TryGetValue(processId, out var entry)) return;
long deltaTicks;
if (enabled)
{
// Calculate delta: (desired fake time) - (current real UTC time)
deltaTicks = fakeUtc.Ticks - DateTime.UtcNow.Ticks;
}
else
{
deltaTicks = 0;
}
entry.Shm.Write(new MockTimeInfo
{
FakeUtcTicks = fakeUtc.Ticks,
DeltaTicks = deltaTicks,
Enabled = enabled ? 1 : 0
});
}
@@ -100,7 +111,7 @@ namespace TimeMocker.UI.Core
public void Eject(int processId)
{
if (!_injected.TryGetValue(processId, out var entry)) return;
entry.Shm.Write(new MockTimeInfo { Enabled = 0 }); // disable mock first
entry.Shm.Write(new MockTimeInfo { Enabled = 0, DeltaTicks = 0 }); // disable mock first
entry.Shm.Dispose();
_injected.Remove(processId);
Log($"Ejected from [{processId}] {entry.ProcessName}");
+2 -2
View File
@@ -46,7 +46,7 @@ namespace TimeMocker.UI.Core
[StructLayout(LayoutKind.Sequential)]
public struct MockTimeInfo
{
public long FakeUtcTicks;
public int Enabled;
public long DeltaTicks; // Offset to add to DateTime.UtcNow.Ticks (can be negative)
public int Enabled; // 1 = mock active, 0 = passthrough
}
}
+11 -60
View File
@@ -25,7 +25,6 @@ namespace TimeMocker.UI.Forms
"timemocker-config.json");
public bool AutoInjectEnabled { get; set; } = true;
public bool AutoAdvanceEnabled { get; set; } = true;
public List<PatternRuleDto> Patterns { get; set; } = new List<PatternRuleDto>();
public void Save()
@@ -70,7 +69,6 @@ namespace TimeMocker.UI.Forms
private CheckBox chkMockEnabled;
private Button btnApply;
private Label lblPreview;
private CheckBox chkAutoAdvance;
// -- Patterns tab
private DataGridView dgvPatterns;
@@ -83,11 +81,6 @@ namespace TimeMocker.UI.Forms
private RichTextBox rtbLog;
private Button btnClearLog;
// Time advancing
private Timer _advanceTimer;
private DateTime _fakeTimeBase;
private DateTime _advanceStartReal;
public MainForm()
{
_config = AppConfig.Load();
@@ -112,7 +105,6 @@ namespace TimeMocker.UI.Forms
// Load config settings
chkWatcherEnabled.Checked = _config.AutoInjectEnabled;
chkAutoAdvance.Checked = _config.AutoAdvanceEnabled;
foreach (var pattern in _config.Patterns)
{
_watcher.AddRule(new PatternRule
@@ -194,21 +186,10 @@ namespace TimeMocker.UI.Forms
ApplyTime();
};
chkAutoAdvance = new CheckBox
{
Text = "Auto-advance time",
ForeColor = Color.FromArgb(220, 220, 220),
Width = 140,
Height = 30,
Margin = new Padding(8, 12, 4, 0),
Checked = true
};
chkAutoAdvance.CheckedChanged += ToggleAutoAdvance;
lblPreview = new Label
{
AutoSize = false,
Width = 260,
Width = 300,
Height = 20,
ForeColor = Color.FromArgb(180, 180, 180),
Font = new Font("Segoe UI", 8.5f, FontStyle.Italic),
@@ -217,8 +198,7 @@ namespace TimeMocker.UI.Forms
timeFlow.Controls.AddRange(new Control[]
{
chkMockEnabled, dtpDate, dtpTime, btnApply, btnSetNow,
chkAutoAdvance, lblPreview
chkMockEnabled, dtpDate, dtpTime, btnApply, btnSetNow, lblPreview
});
grpTime.Controls.Add(timeFlow);
@@ -247,10 +227,6 @@ namespace TimeMocker.UI.Forms
Controls.Add(tabMain);
Controls.Add(grpTime);
// advance timer
_advanceTimer = new Timer { Interval = 1000 };
_advanceTimer.Tick += AdvanceTick;
}
// =====================================================================
@@ -573,52 +549,28 @@ namespace TimeMocker.UI.Forms
_watcher.FakeUtc = dt;
_watcher.MockEnabled = chkMockEnabled.Checked;
if (chkAutoAdvance.Checked)
{
_fakeTimeBase = GetFakeTime();
_advanceStartReal = DateTime.Now;
}
UpdateTimePreview();
}
private void UpdateTimePreview()
{
var dt = GetFakeTime();
lblPreview.Text = chkMockEnabled.Checked
? $"Fake: {dt:yyyy-MM-dd HH:mm:ss} (local)"
: "Pass-through (real time)";
}
private void ToggleAutoAdvance(object sender, EventArgs e)
{
if (chkAutoAdvance.Checked)
if (chkMockEnabled.Checked)
{
_fakeTimeBase = GetFakeTime();
_advanceStartReal = DateTime.Now;
_advanceTimer.Start();
// Calculate what the current offset is
var realNow = DateTime.Now;
var delta = dt - realNow;
var deltaStr = delta.TotalSeconds >= 0
? $"+{delta.TotalSeconds:F0}s"
: $"{delta.TotalSeconds:F0}s";
lblPreview.Text = $"Fake: {dt:yyyy-MM-dd HH:mm:ss} (local, offset {deltaStr})";
}
else
{
_advanceTimer.Stop();
lblPreview.Text = "Pass-through (real time)";
}
}
private void AdvanceTick(object sender, EventArgs e)
{
if (!chkMockEnabled.Checked) return;
var elapsed = DateTime.Now - _advanceStartReal;
var advanced = _fakeTimeBase + elapsed;
// Silently update dtpDate/dtpTime without triggering ValueChanged loop
dtpDate.ValueChanged -= (s, ev) => UpdateTimePreview();
dtpTime.ValueChanged -= (s, ev) => UpdateTimePreview();
dtpDate.Value = advanced;
dtpTime.Value = advanced;
dtpDate.ValueChanged += (s, ev) => UpdateTimePreview();
dtpTime.ValueChanged += (s, ev) => UpdateTimePreview();
ApplyTime();
}
// =====================================================================
// Helpers
// =====================================================================
@@ -738,7 +690,6 @@ namespace TimeMocker.UI.Forms
{
// Save config
_config.AutoInjectEnabled = chkWatcherEnabled.Checked;
_config.AutoAdvanceEnabled = chkAutoAdvance.Checked;
_config.Patterns.Clear();
foreach (DataGridViewRow row in dgvPatterns.Rows)
{