Инструмент командной строки захвата экрана работает из командной строки, но при запуске изнутри пользовательского интерфейса - PullRequest
0 голосов
/ 17 января 2019

Быстрая версия: В моем проекте у меня есть инструмент командной строки, который делает скриншоты всех окон на компьютере (инструмент сбора ошибок для тестирования нашего продукта). Это часть командной строки CollectSystemLogs.exe, которая собирает множество вещей, скриншоты просто как один элемент.

У меня есть небольшой пользовательский интерфейс (CollectUSLogs.exe), который позволяет тестировщику / пользователю выбирать, какие элементы они хотят выбрать. Это просто интерфейс пользователя, с командной строкой CollectSystemLogs.exe, выполняющей всю реальную работу (с параметрами, указывающими, что собирать).

Я могу запустить командную строку CollectSystemLogs.exe из командной строки, и все скриншоты собраны просто отлично.

Однако, когда я запускаю инструмент пользовательского интерфейса CollectUSLogs.exe и выбираю скриншоты, он захватывает только несколько, а затем кажется зависшим или что-то в этом роде. Это останавливается, и я не могу понять, почему. К сожалению, поскольку это процесс, запускаемый пользовательским интерфейсом, я не могу отладить его, и если я запускаю только командную строку, он работает.


Соответствующий код:

Это код для сбора снимков экрана (пожалуйста, не обращайте внимания на все подробные записи в журналы ..... выполняйте отладку старой школы printf).

/// <summary>Gets images of each window on the screen.</summary>
public static void CaptureWindows(string savePath)
{
    LogManager.LogDebugMessage($"Starting CaptureWindows({savePath})");
    AutomationElementCollection desktopChildren = AutomationElement.RootElement.FindAll(TreeScope.Children, Condition.TrueCondition);
    int windowCount = 1;

    LogManager.LogDebugMessage($"{desktopChildren.Count} desktopChildren (windows) found.");

    foreach (AutomationElement window in desktopChildren)
    {
        LogManager.LogDebugMessageConsole($"Capturing window [{window.Current.Name}]");


        Rect rect = window.Current.BoundingRectangle;
        if (Double.IsInfinity(rect.Width) || Double.IsInfinity(rect.Height))
        {
            LogManager.LogErrorMessageConsole($"[{window.Current.Name}] has at leat one infinite dimension.");
            LogManager.LogErrorMessageConsole($"w: {rect.Width}, h: {rect.Height}");
        }

        try
        {
            // TODO: Get rid of unneeded debug log prints
            LogManager.LogDebugMessage("In try{}");
            using (var bitmap = new Bitmap((int)rect.Width, (int)rect.Height))
            {
                LogManager.LogDebugMessage($"Bitmap Created {(int)rect.Width}x{(int)rect.Height}");
                using (Graphics graphic = Graphics.FromImage(bitmap))
                {
                    LogManager.LogDebugMessage($"Graphics created {graphic.ToString()}");
                    IntPtr handleDeviceContext = graphic.GetHdc();
                    var hwnd = (IntPtr)window.Current.NativeWindowHandle;
                    LogManager.LogDebugMessage($"hwnd created {hwnd.ToString()}");
                    if (hwnd == IntPtr.Zero) break;
                    NativeMethods.PrintWindow(hwnd, handleDeviceContext, 0);
                    LogManager.LogDebugMessage("PrintWindow() complete.");
                    graphic.ReleaseHdc(handleDeviceContext);
                }

                // Create File Name for image to be saved
                string fileName = Path.Combine(savePath, windowCount++.ToString("Window00") + ".png");
                LogManager.LogDebugMessage($"Saving {fileName}");
                bitmap.Save(fileName, ImageFormat.Png);
                LogManager.LogDebugMessage($"{fileName} saved");
            }
            LogManager.LogDebugMessage("End of try{}");
        }
        catch (Exception e)
        {
            LogManager.LogExceptionMessageConsole(e);
        }
        LogManager.LogDebugMessage("End of foreach");
    }
    LogManager.LogDebugMessage("Exiting CaptureWindows()");
}

Я вызываю командную строку с этим:

if (!ProcessHelpers.RunCommandProcessCollectOutput(command, args, out output))
{
    MessageBox.Show($"Error running command line tool to collect system logs. Please save {Path.Combine(LogManagerConstants.LogFilePath,LogManagerConstants.LogFileBasename)} for analysis.", 
                @"CollectSystemLogs.exe Execution Error", MessageBoxButtons.OK,
                MessageBoxIcon.Exclamation);
}

И этот код здесь:

public static bool RunCommandProcessCollectOutput(string command, string args, out string output)
{
    // cmd arg /c => run shell and then exit
    // cmd arg /d => disables running of autorun commands from reg 
        //               (may inject extra text into output that could affect parsing)
    string localArgs = $"/d /c {command} {args}";
    string localCommand = @"cmd";

    if (command.StartsWith(@"\\"))
    {
        NetworkHelpers.CreateMapPath(Path.GetDirectoryName(command));
    }

    ProcessStartInfo procStartInfo = new ProcessStartInfo(localCommand, localArgs);

    procStartInfo.UseShellExecute = false; // use shell (command window)
    procStartInfo.CreateNoWindow = false; // Yes, create a window
    procStartInfo.ErrorDialog = false; // Will not show error dialog if process can't start
    procStartInfo.WindowStyle = ProcessWindowStyle.Normal; // Normal type window
    procStartInfo.RedirectStandardOutput = true; // redirect stdout so we can capture
    procStartInfo.RedirectStandardError = true; // redirect stderr so we can capture

    return _RunProcessCollectOutput(procStartInfo, out output);
} 

Финальная часть:

private static bool _RunProcessCollectOutput(ProcessStartInfo procStartInfo, out string output)
{
    bool successful = true;
    output = ""; // init before starting
    LogManager.LogDebugMessage("_RunProcessCollectOutput");
    try
    {
        // Create proc, assign ProcessStartInfo to the proc and start it
        Process proc = new Process();
        proc.StartInfo = procStartInfo;

        // if collecting output, we must wait for process to end in order
        // to collect output.
        LogManager.LogDebugMessage($"Starting {procStartInfo.FileName} {procStartInfo.Arguments}");
        LogManager.LogDebugMessage("[wait forever]");

        successful = proc.Start();

        string temp1 = proc.StandardOutput.ReadToEnd(); // return output if any
        string temp2 = proc.StandardError.ReadToEnd(); // return error output if any

        proc.WaitForExit(); // Wait forever (or until process ends)

        if (temp1.Length > 0)
        {
            output += "[STDOUT]\n" + temp1 + "[/STDOUT]\n";
        }
        if (temp2.Length > 0)
        {
            successful = false;
            output += "[STDERR]\n" + temp2 + "[/STDERR]\n";
        }
    }
    catch (Exception e)
    {
        if (procStartInfo != null)
        {
            LogManager.LogErrorMessage($"Error starting the process {procStartInfo.FileName} {procStartInfo.Arguments}");
        }
        LogManager.LogExceptionMessage(e);
        successful = false;
    }

    return successful;
}

Итак, как я уже сказал ... он прекрасно работает, когда я запускаю из командной строки, но когда эта команда вызывается из интерфейса, таким образом, кажется, что он получает только первые несколько окон, а затем зависает.

Смотрите этот вывод из журнала. Он получает первые несколько (которые кажутся панелями задач на трех мониторах, которые у меня есть, затем он просто зависает. Кажется, он просто останавливается после четвертого, хотя и говорит мне:

40 desktopChildren (windows) найдено.

Я предполагаю, что окно cmd в четвертом является тем, которое запускает инструмент, но я не понимаю, как это должно иметь значение.

[20190116164608|DBG|CollectUSLogs.exe]_RunProcessCollectOutput
[20190116164608|DBG|CollectUSLogs.exe]Starting cmd /d /c C:\XTT\UsbRoot\bin\CollectSystemLogs.exe  -ss -dp D:\
[20190116164608|DBG|CollectUSLogs.exe][wait forever]
[20190116164608|DBG|CollectSystemLogs.exe]Argument: -ss 
[20190116164608|DBG|CollectSystemLogs.exe]Argument: -dp 
[20190116164608|DBG|CollectSystemLogs.exe]D:\
[20190116164608|ERR|CollectSystemLogs.exe]Could not find a part of the path 'e:\host\config\iu\systemoptions.xml'.
[20190116164608|ERR|CollectSystemLogs.exe]   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
[20190116164608|ERR|CollectSystemLogs.exe]   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRigh
[20190116164608|ERR|CollectSystemLogs.exe]ts, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Bo
[20190116164608|ERR|CollectSystemLogs.exe]olean bFromProxy, Boolean useLongPath, Boolean checkHost)
[20190116164608|ERR|CollectSystemLogs.exe]   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 buffe
[20190116164608|ERR|CollectSystemLogs.exe]rSize)
[20190116164608|ERR|CollectSystemLogs.exe]   at System.Xml.XmlDownloadManager.GetStream(Uri uri, ICredentials credentials, IWebProxy proxy, RequestCac
[20190116164608|ERR|CollectSystemLogs.exe]hePolicy cachePolicy)
[20190116164608|ERR|CollectSystemLogs.exe]   at System.Xml.XmlUrlResolver.GetEntity(Uri absoluteUri, String role, Type ofObjectToReturn)
[20190116164608|ERR|CollectSystemLogs.exe]   at System.Xml.XmlTextReaderImpl.FinishInitUriString()
[20190116164608|ERR|CollectSystemLogs.exe]   at System.Xml.XmlTextReaderImpl..ctor(String uriStr, XmlReaderSettings settings, XmlParserContext context
[20190116164608|ERR|CollectSystemLogs.exe], XmlResolver uriResolver)
[20190116164608|ERR|CollectSystemLogs.exe]   at System.Xml.XmlReaderSettings.CreateReader(String inputUri, XmlParserContext inputContext)
[20190116164608|ERR|CollectSystemLogs.exe]   at System.Xml.XmlReader.Create(String inputUri, XmlReaderSettings settings, XmlParserContext inputContext
[20190116164608|ERR|CollectSystemLogs.exe])
[20190116164608|ERR|CollectSystemLogs.exe]   at System.Xml.Linq.XDocument.Load(String uri, LoadOptions options)
[20190116164608|ERR|CollectSystemLogs.exe]   at System.Xml.Linq.XDocument.Load(String uri)
[20190116164608|ERR|CollectSystemLogs.exe]   at XTT.USCartHelpers.get_SerialNumber() in C:\XTT\XTT_Tools\XTT\Helpers\USCartHelpers.cs:line 64
[20190116164608|ERR|CollectSystemLogs.exe]Cannot find Registry32 HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Philips\PHC\Ultrasound
[20190116164608|WRN|CollectSystemLogs.exe]GetOptionalRegValue: Unable to find ProductModel.
[20190116164608|ERR|CollectSystemLogs.exe]Cannot find Registry32 HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Philips\PHC\Ultrasound
[20190116164608|WRN|CollectSystemLogs.exe]GetOptionalRegValue: Unable to find ProductProgram.
[20190116164608|DBG|CollectSystemLogs.exe]Zipfilename: D:\20190116164608_TestCart00_(NOTFOUND)_(NOTFOUND).zip
[20190116164608|DBG|CollectSystemLogs.exe]ZipFolder = C:\temp\20190116164608_TestCart00_(NOTFOUND)_(NOTFOUND)
[20190116164608|WRN|CollectSystemLogs.exe]Can't empty C:\temp\20190116164608_TestCart00_(NOTFOUND)_(NOTFOUND). It doesn't exist.
[20190116164608|INF|CollectSystemLogs.exe]C:\temp\20190116164608_TestCart00_(NOTFOUND)_(NOTFOUND) created
[20190116164608|ERR|CollectSystemLogs.exe]Can't copy SystemOption*.xml in e:\host\config\iu. It doesn't exist.
[20190116164608|ERR|CollectSystemLogs.exe]ERROR collecting SystemOptions.
[20190116164608|ERR|CollectSystemLogs.exe]SystemOptions may not be included in zip file.
[20190116164609|DBG|CollectSystemLogs.exe]Starting CaptureWindows(C:\temp\20190116164608_TestCart00_(NOTFOUND)_(NOTFOUND))
[20190116164624|DBG|CollectSystemLogs.exe]40 desktopChildren (windows) found.
[20190116164624|DBG|CollectSystemLogs.exe]Capturing window []
[20190116164624|DBG|CollectSystemLogs.exe]In try{}
[20190116164624|DBG|CollectSystemLogs.exe]Bitmap Created 1920x40
[20190116164624|DBG|CollectSystemLogs.exe]Graphics created System.Drawing.Graphics
[20190116164624|DBG|CollectSystemLogs.exe]hwnd created 2626768
[20190116164624|DBG|CollectSystemLogs.exe]PrintWindow() complete.
[20190116164624|DBG|CollectSystemLogs.exe]Saving C:\temp\20190116164608_TestCart00_(NOTFOUND)_(NOTFOUND)\Window01.png
[20190116164624|DBG|CollectSystemLogs.exe]C:\temp\20190116164608_TestCart00_(NOTFOUND)_(NOTFOUND)\Window01.png saved
[20190116164624|DBG|CollectSystemLogs.exe]End of try{}
[20190116164624|DBG|CollectSystemLogs.exe]End of foreach
[20190116164624|DBG|CollectSystemLogs.exe]Capturing window []
[20190116164624|DBG|CollectSystemLogs.exe]In try{}
[20190116164624|DBG|CollectSystemLogs.exe]Bitmap Created 1080x40
[20190116164624|DBG|CollectSystemLogs.exe]Graphics created System.Drawing.Graphics
[20190116164624|DBG|CollectSystemLogs.exe]hwnd created 66184
[20190116164624|DBG|CollectSystemLogs.exe]PrintWindow() complete.
[20190116164624|DBG|CollectSystemLogs.exe]Saving C:\temp\20190116164608_TestCart00_(NOTFOUND)_(NOTFOUND)\Window02.png
[20190116164624|DBG|CollectSystemLogs.exe]C:\temp\20190116164608_TestCart00_(NOTFOUND)_(NOTFOUND)\Window02.png saved
[20190116164624|DBG|CollectSystemLogs.exe]End of try{}
[20190116164624|DBG|CollectSystemLogs.exe]End of foreach
[20190116164624|DBG|CollectSystemLogs.exe]Capturing window []
[20190116164624|DBG|CollectSystemLogs.exe]In try{}
[20190116164624|DBG|CollectSystemLogs.exe]Bitmap Created 1920x40
[20190116164624|DBG|CollectSystemLogs.exe]Graphics created System.Drawing.Graphics
[20190116164624|DBG|CollectSystemLogs.exe]hwnd created 333194
[20190116164624|DBG|CollectSystemLogs.exe]PrintWindow() complete.
[20190116164624|DBG|CollectSystemLogs.exe]Saving C:\temp\20190116164608_TestCart00_(NOTFOUND)_(NOTFOUND)\Window03.png
[20190116164624|DBG|CollectSystemLogs.exe]C:\temp\20190116164608_TestCart00_(NOTFOUND)_(NOTFOUND)\Window03.png saved
[20190116164624|DBG|CollectSystemLogs.exe]End of try{}
[20190116164624|DBG|CollectSystemLogs.exe]End of foreach
[20190116164624|DBG|CollectSystemLogs.exe]Capturing window [C:\WINDOWS\SYSTEM32\cmd.exe]
[20190116164624|DBG|CollectSystemLogs.exe]In try{}
[20190116164624|DBG|CollectSystemLogs.exe]Bitmap Created 993x519
[20190116164624|DBG|CollectSystemLogs.exe]Graphics created System.Drawing.Graphics
[20190116164624|DBG|CollectSystemLogs.exe]hwnd created 269574
[20190116164624|DBG|CollectSystemLogs.exe]PrintWindow() complete.
[20190116164624|DBG|CollectSystemLogs.exe]Saving C:\temp\20190116164608_TestCart00_(NOTFOUND)_(NOTFOUND)\Window04.png
[20190116164624|DBG|CollectSystemLogs.exe]C:\temp\20190116164608_TestCart00_(NOTFOUND)_(NOTFOUND)\Window04.png saved
[20190116164624|DBG|CollectSystemLogs.exe]End of try{}
[20190116164624|DBG|CollectSystemLogs.exe]End of foreach

Любые идеи или предложения будут высоко оценены.

Я создал фиктивную командную строку, которая вызывает ту же командную строку (CollectSystemLogs.exe), и она работает с использованием того же вызова метода RunCommandProcessCollectOutput ().

1 Ответ

0 голосов
/ 18 января 2019

ОК ... Оказывается, @ Adam Plocher был прав в первом предположении. Это флаг UseShellExecute.

Я использовал свою оболочку для запуска процесса, который имел UseShellExecute = false, потому что это было необходимо для перенаправления STDOUT и STDERR, которые я хотел, чтобы поместить их в мой журнал.

Я думал, что раньше пытался использовать UseShellExecute = true, но я думаю, что когда я пытался, я получил ошибку, потому что он все еще пытался перенаправить эти потоки, и я, должно быть, остановился на этом.

Я использовал свою другую обертку, которая имеет UseShellExecute = true, но не дает мне STDOUT и STDERR, и это работает. Я думаю, я могу с этим смириться, так как в любом случае достаточно подробного ведения журнала в моем коде.

Я до сих пор не знаю, ПОЧЕМУ так ведет себя при запуске процесса с UseShellExecute = false;

...