Skip to content

Commit

Permalink
added journal commands
Browse files Browse the repository at this point in the history
  • Loading branch information
dosymep committed Oct 18, 2022
1 parent 32b3719 commit b32a490
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 0 deletions.
81 changes: 81 additions & 0 deletions RevitCoreConsole/ConsoleCommands/JournalCommand.cs
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);
}
}
}
}
7 changes: 7 additions & 0 deletions RevitCoreConsole/ConsoleCommands/JournalPipelineCommand.cs
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();
}
}
}
91 changes: 91 additions & 0 deletions RevitCoreConsole/Utils/NativeMethods.cs
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;
}
}
}

0 comments on commit b32a490

Please sign in to comment.