-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
179 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.IO; | ||
using System.Linq; | ||
|
||
using dosymep.Revit.Engine; | ||
|
||
using RevitCoreConsole.Utils; | ||
|
||
using Timer = System.Timers.Timer; | ||
|
||
namespace RevitCoreConsole.ConsoleCommands { | ||
internal class JournalCommand : BaseCommand { | ||
public static IDictionary<string, string> _windowTitles = | ||
new Dictionary<string, string>(StringComparer.CurrentCultureIgnoreCase) { | ||
{"RUS", "Ошибка при работе с журналом"}, {"ENU", "Journal Error"} | ||
}; | ||
|
||
private readonly Timer _timer; | ||
private Process _currentProcess; | ||
|
||
private bool _isForceClose; | ||
|
||
public JournalCommand() { | ||
_timer = new Timer() {Interval = 1000}; | ||
} | ||
|
||
public string JournalPath { get; set; } | ||
|
||
public string WindowTitle { | ||
get { | ||
if(_windowTitles.TryGetValue(LanguageCode.Code, out string value)) { | ||
return value; | ||
} | ||
|
||
return string.Empty; | ||
} | ||
} | ||
|
||
public override void Execute() { | ||
var revitEnginePath = GetAppSettingsValue(nameof(RevitContextOptions), | ||
nameof(RevitContext.RevitEnginePath), RevitContext.GetDefaultRevitEnginePath()); | ||
|
||
var startInfo = new ProcessStartInfo() { | ||
UseShellExecute = false, | ||
RedirectStandardError = true, | ||
RedirectStandardOutput = true, | ||
FileName = Path.Combine(revitEnginePath, "Revit.exe"), | ||
Arguments = $"/language {LanguageCode.Code} \"{JournalPath}\"" | ||
}; | ||
|
||
_timer.Start(); | ||
_timer.Elapsed += (s, e) => KillAppIfFreeze(); | ||
|
||
Logger.Information("Launch REVIT process: {@RevitProcessId}", _currentProcess?.Id); | ||
|
||
_currentProcess = Process.Start(startInfo); | ||
_currentProcess?.WaitForExit(); | ||
|
||
Logger.Information("Exited REVIT process: {@RevitProcessId}", _currentProcess?.Id); | ||
|
||
if(_isForceClose) { | ||
throw new Exception("Revit Journal have error."); | ||
} | ||
} | ||
|
||
private void KillAppIfFreeze() { | ||
string[] windows = NativeMethods.GetRootWindowsOfProcess(_currentProcess) | ||
.Select(item => NativeMethods.GetWindowTitle(item)) | ||
.ToArray(); | ||
|
||
if(windows.Contains(WindowTitle)) { | ||
_isForceClose = true; | ||
|
||
_currentProcess?.Kill(); | ||
Logger.Information("Force close REVIT process: {@RevitProcessId}", _currentProcess?.Id); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
namespace RevitCoreConsole.ConsoleCommands { | ||
internal class JournalPipelineCommand : BaseCommand { | ||
public override void Execute() { | ||
throw new System.NotImplementedException(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Runtime.InteropServices; | ||
using System.Text; | ||
|
||
namespace RevitCoreConsole.Utils | ||
{ | ||
public class NativeMethods | ||
{ | ||
[DllImport("user32.dll")] | ||
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); | ||
|
||
[DllImport("user32.Dll")] | ||
[return: MarshalAs(UnmanagedType.Bool)] | ||
private static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam); | ||
|
||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] | ||
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); | ||
|
||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] | ||
private static extern int GetWindowTextLength(IntPtr hWnd); | ||
|
||
private delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam); | ||
|
||
public static string GetWindowTitle(IntPtr hWnd) | ||
{ | ||
if (hWnd == IntPtr.Zero) | ||
{ | ||
throw new ArgumentNullException(nameof(hWnd)); | ||
} | ||
|
||
int length = GetWindowTextLength(hWnd) + 1; | ||
var title = new StringBuilder(length); | ||
GetWindowText(hWnd, title, length); | ||
|
||
return title.ToString(); | ||
} | ||
|
||
public static IEnumerable<IntPtr> GetRootWindowsOfProcess(Process process) | ||
{ | ||
if (process == null) | ||
{ | ||
throw new ArgumentNullException(nameof(process)); | ||
} | ||
|
||
IEnumerable<IntPtr> rootWindows = GetChildWindows(IntPtr.Zero); | ||
foreach (IntPtr hWnd in rootWindows) | ||
{ | ||
GetWindowThreadProcessId(hWnd, out uint lpdwProcessId); | ||
if (lpdwProcessId == process.Id) | ||
{ | ||
yield return hWnd; | ||
} | ||
} | ||
} | ||
|
||
private static IEnumerable<IntPtr> GetChildWindows(IntPtr parent) | ||
{ | ||
var result = new List<IntPtr>(); | ||
GCHandle listHandle = GCHandle.Alloc(result); | ||
try | ||
{ | ||
var childProc = new Win32Callback(EnumWindow); | ||
EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle)); | ||
} | ||
finally | ||
{ | ||
if (listHandle.IsAllocated) | ||
{ | ||
listHandle.Free(); | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
|
||
private static bool EnumWindow(IntPtr handle, IntPtr pointer) | ||
{ | ||
GCHandle gch = GCHandle.FromIntPtr(pointer); | ||
var list = gch.Target as List<IntPtr>; | ||
if (list == null) | ||
{ | ||
throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>"); | ||
} | ||
|
||
list.Add(handle); | ||
return true; | ||
} | ||
} | ||
} |