gpt4 book ai didi

c# - 消除运行连续 exe 文件的闪烁

转载 作者:可可西里 更新时间:2023-11-01 12:31:08 26 4
gpt4 key购买 nike

我有几个按如下方式运行的 .exe 文件:

   public void RunCalculator(Calculator calculator)
{
var query = Path.Combine(EpiPath, calculator.ExeName + ".exe");

if (File.Exists(Path.Combine(EpiPath, "ffs.exe")))
{
var p = new Process();
p.StartInfo.FileName = query;
p.StartInfo.WorkingDirectory = EpiPath;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo.Arguments = String.Join(" ", calculator.Arguments);
p.Start();
p.WaitForExit();
}
else throw new InvalidOperationException();
}

此代码有效,但仍然有一些闪烁是由于多次运行 exe 文件引起的。有没有什么方法可以消除闪烁,因为用户体验它真的很烦人,因为它会持续几秒钟(有相当多的 exe 正在运行)。

我尝试使用一个任务在不同的线程上执行它,但由于每个 exe 都依赖于前一个(它写入一个文件)的工作,我得到一个 IO 异常。

似乎 exe 文件只有在 ProcessPriority 设置为 Realtime 时才能工作。

编辑:

关于我最近尝试的更多细节:正如@Jack Hughes 建议的那样,我尝试使用后台 worker 来解决这个问题:

这是我做的:

我在后台 worker 上调用 RunWorkerAsync() 函数,后台 worker 依次为每个计算器调用 RunCalculator 函数。闪烁仍然存在。

编辑2:我创建了一个详细的存储库,其中包含我运行 exe 文件的方式、exe 文件和 Old Fox 建议的 ProcessHelper 类。您可以在自述文件中找到有关如何使用存储库的说明。

存储库链接:https://github.com/interdrift/epiwin-flick

最佳答案

当我使用 C# 创建 ActiveX 扩展时,我遇到了与您描述的相同的“闪烁”问题。该扩展程序必须启动一个隐藏的控制台应用程序,但是每次我启动该应用程序时,控制台都会出现几毫秒。

为了解决这个问题,我尝试了很多方法,例如:获取 Process 类的源代码并对其进行调试,UAC 检查,VM' s vs 真机等

我找到的解决方案是使用 Win32Api。以下代码段启动了一个没有“闪烁”的新进程:

public class ProcessHelper
{

public const Int32 USE_STD_HANDLES = 0x00000100;
public const Int32 STD_OUTPUT_HANDLE = -11;
public const Int32 STD_ERROR_HANDLE = -12;

//this flag instructs StartProcessWithLogonW to consider the value StartupInfo.showWindow when creating the process
public const Int32 STARTF_USESHOWWINDOW = 0x00000001;



public static ProcessStartResult StartProcess(string exe,
string[] args = null,
bool isHidden = false,
bool waitForExit = false,
uint waitTimeout = 0)
{
string command;

var startupInfo = CreateStartupInfo(exe, args, isHidden, out command);

ProcessInformation processInfo;

var processSecAttributes = new SecurityAttributes();

processSecAttributes.Length = Marshal.SizeOf(processSecAttributes);

var threadSecAttributes = new SecurityAttributes();

threadSecAttributes.Length = Marshal.SizeOf(threadSecAttributes);

CreationFlags creationFlags = 0;

if (isHidden)
{
creationFlags = CreationFlags.CreateNoWindow;
}

var started = Win32Api.CreateProcess(exe,
command,
ref processSecAttributes,
ref threadSecAttributes,
false,
Convert.ToInt32(creationFlags),
IntPtr.Zero,
null,
ref startupInfo,
out processInfo);


var result = CreateProcessStartResult(waitForExit, waitTimeout, processInfo, started);

return result;
}

private static StartupInfo CreateStartupInfo(string exe, string[] args, bool isHidden, out string command)
{
var startupInfo = new StartupInfo();

startupInfo.Flags &= USE_STD_HANDLES;
startupInfo.StdOutput = (IntPtr) STD_OUTPUT_HANDLE;
startupInfo.StdError = (IntPtr) STD_ERROR_HANDLE;

if (isHidden)
{
startupInfo.ShowWindow = 0;
startupInfo.Flags = STARTF_USESHOWWINDOW;
}

var argsWithExeName = new string[args.Length + 1];

argsWithExeName[0] = exe;

args.CopyTo(argsWithExeName, 1);

var argsString = ToCommandLineArgsString(argsWithExeName);

command = argsString;

return startupInfo;
}

private static string ToCommandLineArgsString(Array array)
{
var argumentsBuilder = new StringBuilder();

foreach (var item in array)
{
if (item != null)
{
var escapedArgument = item.ToString().Replace("\"", "\"\"");
argumentsBuilder.AppendFormat("\"{0}\" ", escapedArgument);
}
}

return argumentsBuilder.ToString();
}

private static ProcessStartResult CreateProcessStartResult(bool waitForExit, uint waitTimeout,
ProcessInformation processInfo, bool started)
{
uint exitCode = 0;
var hasExited = false;

if (started && waitForExit)
{
var waitResult = Win32Api.WaitForSingleObject(processInfo.Process, waitTimeout);

if (waitResult == WaitForSingleObjectResult.WAIT_OBJECT_0)
{
Win32Api.GetExitCodeProcess(processInfo.Process, ref exitCode);
hasExited = true;
}
}

var result = new ProcessStartResult()
{
ExitCode = (int) exitCode,
Started = started,
HasExited = hasExited
};
return result;
}

}

[Flags]
public enum CreationFlags
{
CreateSuspended = 0x00000004,

CreateNewConsole = 0x00000010,

CreateNewProcessGroup = 0x00000200,

CreateNoWindow = 0x08000000,

CreateUnicodeEnvironment = 0x00000400,

CreateSeparateWowVdm = 0x00000800,

CreateDefaultErrorMode = 0x04000000,
}

public struct ProcessInformation
{
public IntPtr Process { get; set; }
public IntPtr Thread { get; set; }
public int ProcessId { get; set; }
public int ThreadId { get; set; }
}

public class ProcessStartResult
{
public bool Started { get; set; }

public int ExitCode { get; set; }

public bool HasExited { get; set; }

public Exception Error { get; set; }

}

[StructLayout(LayoutKind.Sequential)]
public struct SecurityAttributes
{
public int Length;
public IntPtr SecurityDescriptor;
public int InheritHandle;
}

public struct StartupInfo
{
public int Cb;
public String Reserved;
public String Desktop;
public String Title;
public int X;
public int Y;
public int XSize;
public int YSize;
public int XCountChars;
public int YCountChars;
public int FillAttribute;
public int Flags;
public UInt16 ShowWindow;
public UInt16 Reserved2;
public byte Reserved3;
public IntPtr StdInput;
public IntPtr StdOutput;
public IntPtr StdError;
}

public static class WaitForSingleObjectResult
{
/// <summary>
/// The specified object is a mutex object that was not released by the thread that owned the mutex
/// object before the owning thread terminated. Ownership of the mutex object is granted to the
/// calling thread and the mutex state is set to nonsignaled
/// </summary>
public const UInt32 WAIT_ABANDONED = 0x00000080;
/// <summary>
/// The state of the specified object is signaled.
/// </summary>
public const UInt32 WAIT_OBJECT_0 = 0x00000000;
/// <summary>
/// The time-out interval elapsed, and the object's state is nonsignaled.
/// </summary>
public const UInt32 WAIT_TIMEOUT = 0x00000102;
}

public class Win32Api
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool GetExitCodeProcess(IntPtr process, ref UInt32 exitCode);

[DllImport("Kernel32.dll", SetLastError = true)]
public static extern UInt32 WaitForSingleObject(IntPtr handle, UInt32 milliseconds);

[DllImport("kernel32.dll")]
public static extern bool CreateProcess
(string lpApplicationName,
string lpCommandLine,
ref SecurityAttributes lpProcessAttributes,
ref SecurityAttributes lpThreadAttributes,
bool bInheritHandles,
Int32 dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
[In] ref StartupInfo lpStartupInfo,
out ProcessInformation lpProcessInformation);
}

编辑:

我用 startupInfo.ShowWindow = 7 尝试了上面的代码(它应该在不窃取焦点的情况下启动应用程序),一些应用程序仍然窃取焦点,因此我推断其中一些应用程序使用一种Bring to front方法....

我在 WPF 窗口中稍微玩了一下您的代码,然后我发现如果 UI 处于 Sleep 应用程序不会失去焦点:

    private  void Button_Click(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(() =>
{

//Provide path to epi
string epiPath = @"c:/EPISUITE41";
Level3ntCalculator cl = new Level3ntCalculator();
var runner = new Calculators.Epi.Runners.ProcessRunner(epiPath);


runner.WriteXSmilesFiles("CCCCC1CCCCCCC1");
cl.Calculate(runner);

});

Thread.Sleep(2000);
}

这不是一个好的解决方案!但是,只有在启动其中一个进程时才需要 sleep ……所以我尝试使用此信息:

    private  void Button_Click(object sender, RoutedEventArgs e)
{
var ac = new Action(() => Application.Current.Dispatcher.Invoke(
() =>
{
Thread.Sleep(50);
}));
Task.Factory.StartNew(() =>
{

//Provide path to epi
string epiPath = @"c:/EPISUITE41";
Level3ntCalculator cl = new Level3ntCalculator();
var runner = new Calculators.Epi.Runners.ProcessRunner(epiPath, ac);


runner.WriteXSmilesFiles("CCCCC1CCCCCCC1");
cl.Calculate(runner);

});

}

然后我更改了 ProcessRunner:

    public void RunCalculator(Calculator calculator)
{
//bla bla bla...
new Thread(new ThreadStart(_action)).Start();
p.Start();
//...
}

在这段代码中,您在 UI 线程中执行 Thread.Sleep 的时间很短(用户永远不会知道...)。

这是一个糟糕的解决方案...但是它解决了问题。

关于c# - 消除运行连续 exe 文件的闪烁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31334929/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com