diff --git a/YaeAchievement.csproj b/YaeAchievement.csproj index b769af7..6ad305e 100644 --- a/YaeAchievement.csproj +++ b/YaeAchievement.csproj @@ -9,4 +9,8 @@ res\app.manifest + + + + diff --git a/src/Events/IEventBase.cs b/src/Events/IEventBase.cs deleted file mode 100644 index 8bcec9c..0000000 --- a/src/Events/IEventBase.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace YaeAchievement.Events; - -public interface IEventBase { - -} \ No newline at end of file diff --git a/src/Events/PipeRecvEvent.cs b/src/Events/PipeRecvEvent.cs deleted file mode 100644 index 42dbe6e..0000000 --- a/src/Events/PipeRecvEvent.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace YaeAchievement.Events; - -public class PipeRecvEvent : IEventBase { - - private readonly byte[] _data; - - public PipeRecvEvent(string content) { - _data = Convert.FromBase64String(content); - } - - public byte[] GetData() { - return _data; - } -} \ No newline at end of file diff --git a/src/Program.cs b/src/Program.cs index 406ebc2..c18b624 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -2,67 +2,13 @@ using System.Diagnostics; using System.IO.Pipes; using YaeAchievement; -using YaeAchievement.Events; using YaeAchievement.Win32; -// ReSharper disable once UnusedLocalFunctionReturnValue -Thread StartAndWaitResult(string exePath, Func onEvent) { - if (!Injector.CreateProcess(exePath, out var hProcess, out var hThread, out var pid)) { - Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("ICreateProcess fail")); - } - if (Injector.LoadLibraryAndInject(hProcess, GlobalVars.LibName) != 0) { - if (!Native.TerminateProcess(hProcess, 0)) { - Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail")); - } - } - if (Native.ResumeThread(hThread) == 0xFFFFFFFF) { - var e = new Win32Exception(); - if (!Native.TerminateProcess(hProcess, 0)) { - new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail"); - } - Environment.Exit(e.PrintMsgAndReturnErrCode("ResumeThread fail")); - } - if (!Native.CloseHandle(hProcess)) { - Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("CloseHandle fail")); - } - var proc = Process.GetProcessById(Convert.ToInt32(pid)); - proc.EnableRaisingEvents = true; - proc.Exited += (_, _) => { - if (GlobalVars.UnexpectedExit) { - Console.WriteLine($"Game process exit at {proc.ExitTime:HH:mm:ss}"); - Environment.Exit(114514); - } - }; - var ts = new ThreadStart(() => { - var server = new NamedPipeServerStream(GlobalVars.PipeName); - server.WaitForConnection(); - var reader = new StreamReader(server); - while (true) { - var line = reader.ReadLine(); - if (line?.Length > 0) { - if (onEvent(new PipeRecvEvent(line))) { - break; - } - server.Disconnect(); - server.WaitForConnection(); - } - } - }); - var th = new Thread(ts); - th.Start(); - return th; -} -StartAndWaitResult(@"D:\Genshin Impact Dev\2.8\YuanShen.exe", evt => { - switch (evt) { - case PipeRecvEvent @event: { - var bytes = @event.GetData(); - GlobalVars.UnexpectedExit = false; - Console.WriteLine("On PRE"); - Console.WriteLine(Convert.ToBase64String(bytes)); - return false; - } - default: - return false; - } +Utils.StartAndWaitResult(@"D:\Genshin Impact Dev\2.8\YuanShen.exe", str => { + GlobalVars.UnexpectedExit = false; + //AchievementAllDataNotify.Parser.ParseFrom(Convert.FromBase64String(str)).List; + //var notify = Serializer.Deserialize(stream)!; + //notify.list; + return false; }); diff --git a/src/Proto/AchievementAllDataNotify.cs b/src/Proto/AchievementAllDataNotify.cs new file mode 100644 index 0000000..6337a5f --- /dev/null +++ b/src/Proto/AchievementAllDataNotify.cs @@ -0,0 +1,572 @@ +// +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: AchievementAllDataNotify.proto +// +#pragma warning disable 1591, 0612, 3021, 8981 +#region Designer generated code + +using pb = global::Google.Protobuf; +using pbc = global::Google.Protobuf.Collections; +using pbr = global::Google.Protobuf.Reflection; +using scg = global::System.Collections.Generic; +/// Holder for reflection information generated from AchievementAllDataNotify.proto +public static partial class AchievementAllDataNotifyReflection { + + #region Descriptor + /// File descriptor for AchievementAllDataNotify.proto + public static pbr::FileDescriptor Descriptor { + get { return descriptor; } + } + private static pbr::FileDescriptor descriptor; + + static AchievementAllDataNotifyReflection() { + byte[] descriptorData = global::System.Convert.FromBase64String( + string.Concat( + "Ch5BY2hpZXZlbWVudEFsbERhdGFOb3RpZnkucHJvdG8iugEKC0FjaGlldmVt", + "ZW50EgoKAmlkGAEgASgNEiMKBnN0YXR1cxgCIAEoDjITLkFjaGlldmVtZW50", + "LlN0YXR1cxIPCgdjdXJyZW50GAMgASgNEg8KB3JlcXVpcmUYBCABKA0SEQoJ", + "dGltZXN0YW1wGAUgASgNIkUKBlN0YXR1cxILCgdJTlZBTElEEAASDgoKVU5G", + "SU5JU0hFRBABEgwKCEZJTklTSEVEEAISEAoMUkVXQVJEX1RBS0VOEAMiNgoY", + "QWNoaWV2ZW1lbnRBbGxEYXRhTm90aWZ5EhoKBGxpc3QYBSADKAsyDC5BY2hp", + "ZXZlbWVudGIGcHJvdG8z")); + descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, + new pbr::FileDescriptor[] { }, + new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] { + new pbr::GeneratedClrTypeInfo(typeof(global::Achievement), global::Achievement.Parser, new[]{ "ID", "Status", "Current", "Require", "Timestamp" }, null, new[]{ typeof(global::Achievement.Types.Status) }, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::AchievementAllDataNotify), global::AchievementAllDataNotify.Parser, new[]{ "List" }, null, null, null, null) + })); + } + #endregion + +} +#region Messages +public sealed partial class Achievement : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage +#endif +{ + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new Achievement()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::AchievementAllDataNotifyReflection.Descriptor.MessageTypes[0]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Achievement() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Achievement(Achievement other) : this() { + id_ = other.id_; + status_ = other.status_; + current_ = other.current_; + require_ = other.require_; + timestamp_ = other.timestamp_; + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public Achievement Clone() { + return new Achievement(this); + } + + /// Field number for the "id" field. + public const int IDFieldNumber = 1; + private uint id_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public uint ID { + get { return id_; } + set { + id_ = value; + } + } + + /// Field number for the "status" field. + public const int StatusFieldNumber = 2; + private global::Achievement.Types.Status status_ = global::Achievement.Types.Status.Invalid; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public global::Achievement.Types.Status Status { + get { return status_; } + set { + status_ = value; + } + } + + /// Field number for the "current" field. + public const int CurrentFieldNumber = 3; + private uint current_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public uint Current { + get { return current_; } + set { + current_ = value; + } + } + + /// Field number for the "require" field. + public const int RequireFieldNumber = 4; + private uint require_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public uint Require { + get { return require_; } + set { + require_ = value; + } + } + + /// Field number for the "timestamp" field. + public const int TimestampFieldNumber = 5; + private uint timestamp_; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public uint Timestamp { + get { return timestamp_; } + set { + timestamp_ = value; + } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as Achievement); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(Achievement other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (ID != other.ID) return false; + if (Status != other.Status) return false; + if (Current != other.Current) return false; + if (Require != other.Require) return false; + if (Timestamp != other.Timestamp) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + if (ID != 0) hash ^= ID.GetHashCode(); + if (Status != global::Achievement.Types.Status.Invalid) hash ^= Status.GetHashCode(); + if (Current != 0) hash ^= Current.GetHashCode(); + if (Require != 0) hash ^= Require.GetHashCode(); + if (Timestamp != 0) hash ^= Timestamp.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + if (ID != 0) { + output.WriteRawTag(8); + output.WriteUInt32(ID); + } + if (Status != global::Achievement.Types.Status.Invalid) { + output.WriteRawTag(16); + output.WriteEnum((int) Status); + } + if (Current != 0) { + output.WriteRawTag(24); + output.WriteUInt32(Current); + } + if (Require != 0) { + output.WriteRawTag(32); + output.WriteUInt32(Require); + } + if (Timestamp != 0) { + output.WriteRawTag(40); + output.WriteUInt32(Timestamp); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + if (ID != 0) { + output.WriteRawTag(8); + output.WriteUInt32(ID); + } + if (Status != global::Achievement.Types.Status.Invalid) { + output.WriteRawTag(16); + output.WriteEnum((int) Status); + } + if (Current != 0) { + output.WriteRawTag(24); + output.WriteUInt32(Current); + } + if (Require != 0) { + output.WriteRawTag(32); + output.WriteUInt32(Require); + } + if (Timestamp != 0) { + output.WriteRawTag(40); + output.WriteUInt32(Timestamp); + } + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + if (ID != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(ID); + } + if (Status != global::Achievement.Types.Status.Invalid) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Status); + } + if (Current != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Current); + } + if (Require != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Require); + } + if (Timestamp != 0) { + size += 1 + pb::CodedOutputStream.ComputeUInt32Size(Timestamp); + } + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(Achievement other) { + if (other == null) { + return; + } + if (other.ID != 0) { + ID = other.ID; + } + if (other.Status != global::Achievement.Types.Status.Invalid) { + Status = other.Status; + } + if (other.Current != 0) { + Current = other.Current; + } + if (other.Require != 0) { + Require = other.Require; + } + if (other.Timestamp != 0) { + Timestamp = other.Timestamp; + } + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 8: { + ID = input.ReadUInt32(); + break; + } + case 16: { + Status = (global::Achievement.Types.Status) input.ReadEnum(); + break; + } + case 24: { + Current = input.ReadUInt32(); + break; + } + case 32: { + Require = input.ReadUInt32(); + break; + } + case 40: { + Timestamp = input.ReadUInt32(); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 8: { + ID = input.ReadUInt32(); + break; + } + case 16: { + Status = (global::Achievement.Types.Status) input.ReadEnum(); + break; + } + case 24: { + Current = input.ReadUInt32(); + break; + } + case 32: { + Require = input.ReadUInt32(); + break; + } + case 40: { + Timestamp = input.ReadUInt32(); + break; + } + } + } + } + #endif + + #region Nested types + /// Container for nested types declared in the Achievement message type. + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static partial class Types { + public enum Status { + [pbr::OriginalName("INVALID")] Invalid = 0, + [pbr::OriginalName("UNFINISHED")] Unfinished = 1, + [pbr::OriginalName("FINISHED")] Finished = 2, + [pbr::OriginalName("REWARD_TAKEN")] RewardTaken = 3, + } + + } + #endregion + +} + +public sealed partial class AchievementAllDataNotify : pb::IMessage +#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + , pb::IBufferMessage +#endif +{ + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new AchievementAllDataNotify()); + private pb::UnknownFieldSet _unknownFields; + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pb::MessageParser Parser { get { return _parser; } } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public static pbr::MessageDescriptor Descriptor { + get { return global::AchievementAllDataNotifyReflection.Descriptor.MessageTypes[1]; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public AchievementAllDataNotify() { + OnConstruction(); + } + + partial void OnConstruction(); + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public AchievementAllDataNotify(AchievementAllDataNotify other) : this() { + list_ = other.list_.Clone(); + _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public AchievementAllDataNotify Clone() { + return new AchievementAllDataNotify(this); + } + + /// Field number for the "list" field. + public const int ListFieldNumber = 5; + private static readonly pb::FieldCodec _repeated_list_codec + = pb::FieldCodec.ForMessage(42, global::Achievement.Parser); + private readonly pbc::RepeatedField list_ = new pbc::RepeatedField(); + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public pbc::RepeatedField List { + get { return list_; } + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override bool Equals(object other) { + return Equals(other as AchievementAllDataNotify); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public bool Equals(AchievementAllDataNotify other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if(!list_.Equals(other.list_)) return false; + return Equals(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override int GetHashCode() { + int hash = 1; + hash ^= list_.GetHashCode(); + if (_unknownFields != null) { + hash ^= _unknownFields.GetHashCode(); + } + return hash; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void WriteTo(pb::CodedOutputStream output) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + output.WriteRawMessage(this); + #else + list_.WriteTo(output, _repeated_list_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(output); + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) { + list_.WriteTo(ref output, _repeated_list_codec); + if (_unknownFields != null) { + _unknownFields.WriteTo(ref output); + } + } + #endif + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public int CalculateSize() { + int size = 0; + size += list_.CalculateSize(_repeated_list_codec); + if (_unknownFields != null) { + size += _unknownFields.CalculateSize(); + } + return size; + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(AchievementAllDataNotify other) { + if (other == null) { + return; + } + list_.Add(other.list_); + _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); + } + + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + public void MergeFrom(pb::CodedInputStream input) { + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + input.ReadRawMessage(this); + #else + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input); + break; + case 42: { + list_.AddEntriesFrom(input, _repeated_list_codec); + break; + } + } + } + #endif + } + + #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)] + void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input); + break; + case 42: { + list_.AddEntriesFrom(ref input, _repeated_list_codec); + break; + } + } + } + } + #endif +} +#endregion +#endregion Designer generated code diff --git a/src/Utils.cs b/src/Utils.cs new file mode 100644 index 0000000..555279f --- /dev/null +++ b/src/Utils.cs @@ -0,0 +1,55 @@ +using System.ComponentModel; +using System.Diagnostics; +using System.IO.Pipes; +using YaeAchievement.Win32; + +namespace YaeAchievement; + +public static class Utils { + + // ReSharper disable once UnusedMethodReturnValue.Global + public static Thread StartAndWaitResult(string exePath, Func onReceive) { + if (!Injector.CreateProcess(exePath, out var hProcess, out var hThread, out var pid)) { + Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("ICreateProcess fail")); + } + if (Injector.LoadLibraryAndInject(hProcess, GlobalVars.LibName) != 0) { + if (!Native.TerminateProcess(hProcess, 0)) { + Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail")); + } + } + if (Native.ResumeThread(hThread) == 0xFFFFFFFF) { + var e = new Win32Exception(); + if (!Native.TerminateProcess(hProcess, 0)) { + new Win32Exception().PrintMsgAndReturnErrCode("TerminateProcess fail"); + } + Environment.Exit(e.PrintMsgAndReturnErrCode("ResumeThread fail")); + } + if (!Native.CloseHandle(hProcess)) { + Environment.Exit(new Win32Exception().PrintMsgAndReturnErrCode("CloseHandle fail")); + } + var proc = Process.GetProcessById(Convert.ToInt32(pid)); + proc.EnableRaisingEvents = true; + proc.Exited += (_, _) => { + if (GlobalVars.UnexpectedExit) { + Console.WriteLine($"Game process exit at {proc.ExitTime:HH:mm:ss}"); + Environment.Exit(114514); + } + }; + var ts = new ThreadStart(() => { + var server = new NamedPipeServerStream(GlobalVars.PipeName); + server.WaitForConnection(); + using var reader = new StreamReader(server); + while (!proc.HasExited) { + var line = reader.ReadLine(); + if (line?.Length > 0) { + if (onReceive(line)) break; + server.Disconnect(); + server.WaitForConnection(); + } + } + }); + var th = new Thread(ts); + th.Start(); + return th; + } +} \ No newline at end of file