瀏覽代碼

Extension output can be displayed in a message box + Local custom console command output can be copied to clipboard

Source commit: ad5ae7b01fd6acf7e8032c6f8022d5032e71372b
Martin Prikryl 9 年之前
父節點
當前提交
cbc4860eca

+ 0 - 1
source/forms/CustomCommand.cpp

@@ -136,7 +136,6 @@ void __fastcall TCustomCommandDialog::UpdateControls()
   EnableControl(RecursiveCheck, AllowRecursive && (!RemoteFilesCheck->Enabled || !RemoteFilesCheck->Checked));
   EnableControl(ApplyToDirectoriesCheck, AllowApplyToDirectories);
   EnableControl(ShowResultsCheck, RemoteCommand);
-  EnableControl(CopyResultsCheck, RemoteCommand);
   EnableControl(RemoteFilesCheck,
     FLAGCLEAR(FOptions, ccoDisableRemoteFiles) && AllowRemoteFiles &&
     (!RecursiveCheck->Enabled || !RecursiveCheck->Checked));

+ 47 - 10
source/forms/CustomScpExplorer.cpp

@@ -1708,7 +1708,10 @@ void __fastcall TCustomScpExplorerForm::CustomCommand(TStrings * FileList,
 
       Configuration->Usage->Inc(L"RemoteCustomCommandRuns2");
 
-      bool Capture = FLAGSET(ACommand.Params, ccShowResults) || FLAGSET(ACommand.Params, ccCopyResults);
+      bool Capture =
+        FLAGSET(ACommand.Params, ccShowResults) ||
+        FLAGSET(ACommand.Params, ccCopyResults) ||
+        FLAGSET(ACommand.Params, ccShowResultsInMsgBox);
       TCaptureOutputEvent OutputEvent = NULL;
 
       DebugAssert(FCapturedLog == NULL);
@@ -1741,6 +1744,10 @@ void __fastcall TCustomScpExplorerForm::CustomCommand(TStrings * FileList,
           {
             DoConsoleDialog(Terminal, L"", FCapturedLog);
           }
+          else if (FLAGSET(ACommand.Params, ccShowResultsInMsgBox))
+          {
+            MessageDialog(FCapturedLog->Text, qtInformation, qaOK);
+          }
         }
       }
       __finally
@@ -1762,9 +1769,16 @@ void __fastcall TCustomScpExplorerForm::CustomCommand(TStrings * FileList,
 
     Configuration->Usage->Inc(L"LocalCustomCommandRuns2");
 
+    std::unique_ptr<UnicodeString> POutput;
+    if (FLAGSET(ACommand.Params, ccShowResultsInMsgBox) ||
+        FLAGSET(ACommand.Params, ccCopyResults))
+    {
+      POutput.reset(new UnicodeString());
+    }
+
     if (!LocalCustomCommand.IsFileCommand(Command))
     {
-      ExecuteShellChecked(LocalCustomCommand.Complete(Command, true));
+      ExecuteProcessChecked(LocalCustomCommand.Complete(Command, true), POutput.get());
     }
     // remote files?
     else if ((FCurrentSide == osRemote) || LocalFileCommand)
@@ -1838,7 +1852,7 @@ void __fastcall TCustomScpExplorerForm::CustomCommand(TStrings * FileList,
             ProcessLocalDirectory(TempDir, Terminal->MakeLocalFileList, &MakeFileListParam);
           }
 
-          bool NonBlocking = FileListCommand && RemoteFiles;
+          bool NonBlocking = FileListCommand && RemoteFiles && !POutput;
 
           TFileOperationProgressType Progress(&OperationProgress, &OperationFinished);
 
@@ -1869,11 +1883,12 @@ void __fastcall TCustomScpExplorerForm::CustomCommand(TStrings * FileList,
 
               if (NonBlocking)
               {
+                DebugAssert(!POutput);
                 ExecuteShellChecked(ShellCommand);
               }
               else
               {
-                ExecuteShellCheckedAndWait(ShellCommand);
+                ExecuteProcessCheckedAndWait(ShellCommand, POutput.get());
               }
             }
             else if (LocalFileCommand)
@@ -1887,7 +1902,7 @@ void __fastcall TCustomScpExplorerForm::CustomCommand(TStrings * FileList,
                   UnicodeString FileName = RemoteFileList->Strings[Index];
                   TLocalCustomCommand CustomCommand(Data,
                     Terminal->CurrentDirectory, DefaultDownloadTargetDirectory(), FileName, LocalFile, L"");
-                  ExecuteShellCheckedAndWait(CustomCommand.Complete(Command, true));
+                  ExecuteProcessCheckedAndWait(CustomCommand.Complete(Command, true), POutput.get());
                 }
               }
               else if (RemoteFileList->Count == 1)
@@ -1899,7 +1914,7 @@ void __fastcall TCustomScpExplorerForm::CustomCommand(TStrings * FileList,
                   TLocalCustomCommand CustomCommand(
                     Data, Terminal->CurrentDirectory, DefaultDownloadTargetDirectory(),
                     FileName, LocalFileList->Strings[Index], L"");
-                  ExecuteShellCheckedAndWait(CustomCommand.Complete(Command, true));
+                  ExecuteProcessCheckedAndWait(CustomCommand.Complete(Command, true), POutput.get());
                 }
               }
               else
@@ -1915,7 +1930,7 @@ void __fastcall TCustomScpExplorerForm::CustomCommand(TStrings * FileList,
                   TLocalCustomCommand CustomCommand(
                     Data, Terminal->CurrentDirectory, DefaultDownloadTargetDirectory(),
                     FileName, LocalFileList->Strings[Index], L"");
-                  ExecuteShellCheckedAndWait(CustomCommand.Complete(Command, true));
+                  ExecuteProcessCheckedAndWait(CustomCommand.Complete(Command, true), POutput.get());
                 }
               }
             }
@@ -1926,7 +1941,7 @@ void __fastcall TCustomScpExplorerForm::CustomCommand(TStrings * FileList,
                 TLocalCustomCommand CustomCommand(Data,
                   Terminal->CurrentDirectory, DefaultDownloadTargetDirectory(),
                   RemoteFileList->Strings[Index], L"", L"");
-                ExecuteShellCheckedAndWait(CustomCommand.Complete(Command, true));
+                ExecuteProcessCheckedAndWait(CustomCommand.Complete(Command, true), POutput.get());
               }
             }
           }
@@ -2036,7 +2051,7 @@ void __fastcall TCustomScpExplorerForm::CustomCommand(TStrings * FileList,
         TLocalCustomCommand CustomCommand(
           Data, Terminal->CurrentDirectory, DefaultDownloadTargetDirectory(),
           L"", L"", FileList);
-        ExecuteShellChecked(CustomCommand.Complete(Command, true));
+        ExecuteProcessChecked(CustomCommand.Complete(Command, true), POutput.get());
       }
       else
       {
@@ -2054,7 +2069,7 @@ void __fastcall TCustomScpExplorerForm::CustomCommand(TStrings * FileList,
             TLocalCustomCommand CustomCommand(
               Data, Terminal->CurrentDirectory, DefaultDownloadTargetDirectory(),
               FileName, L"", L"");
-            ExecuteShellCheckedAndWait(CustomCommand.Complete(Command, true));
+            ExecuteProcessCheckedAndWait(CustomCommand.Complete(Command, true), POutput.get());
           }
         }
         __finally
@@ -2063,6 +2078,28 @@ void __fastcall TCustomScpExplorerForm::CustomCommand(TStrings * FileList,
         }
       }
     }
+
+    if (POutput.get() != NULL)
+    {
+      // If the output is single-line, we do not want the trailing CRLF, as the CopyToClipboard(TStrings *) does
+      int P = POutput->Pos(sLineBreak);
+      if (P == POutput->Length() - static_cast<int>(strlen(sLineBreak)) + 1)
+      {
+        POutput->SetLength(P - 1);
+      }
+      // Copy even empty output to clipboard
+      if (FLAGSET(ACommand.Params, ccCopyResults))
+      {
+        CopyToClipboard(*POutput);
+      }
+      // But do not show an empty message box.
+      // This way the ShowResultsInMsgBox can be used to suppress a console window of commands with no output
+      if (FLAGSET(ACommand.Params, ccShowResultsInMsgBox) &&
+          !POutput->IsEmpty())
+      {
+        MessageDialog(*POutput, qtInformation, qaOK);
+      }
+    }
   }
 }
 //---------------------------------------------------------------------------

+ 1 - 0
source/windows/GUIConfiguration.cpp

@@ -17,6 +17,7 @@ const int ccLocal = ccUser;
 const int ccShowResults = ccUser << 1;
 const int ccCopyResults = ccUser << 2;
 const int ccRemoteFiles = ccUser << 3;
+const int ccShowResultsInMsgBox = ccUser << 4;
 const int ccSet = 0x80000000;
 //---------------------------------------------------------------------------
 static const unsigned int AdditionaLanguageMask = 0xFFFFFF00;

+ 1 - 0
source/windows/GUIConfiguration.h

@@ -15,6 +15,7 @@ extern const int ccShowResults;
 extern const int ccCopyResults;
 extern const int ccSet;
 extern const int ccRemoteFiles;
+extern const int ccShowResultsInMsgBox;
 //---------------------------------------------------------------------------
 const int soRecurse =         0x01;
 const int soSynchronize =     0x02;

+ 1 - 0
source/windows/GUITools.cpp

@@ -256,6 +256,7 @@ void __fastcall ExecuteShellCheckedAndWait(const UnicodeString Command,
       unsigned long WaitResult;
       do
       {
+        // Same as in ExecuteProcessAndReadOutput
         WaitResult = WaitForSingleObject(ProcessHandle, 200);
         if (WaitResult == WAIT_FAILED)
         {

+ 89 - 2
source/windows/Tools.cpp

@@ -295,9 +295,96 @@ UnicodeString __fastcall StoreFormSize(TForm * Form)
   return FORMAT(L"%d,%d,%s", (Form->Width, Form->Height, SavePixelsPerInch()));
 }
 //---------------------------------------------------------------------------
-void __fastcall ExecuteShellCheckedAndWait(const UnicodeString Command)
+static void __fastcall ExecuteProcessAndReadOutput(const UnicodeString & Command, UnicodeString & Output)
 {
-  ExecuteShellCheckedAndWait(Command, &Application->ProcessMessages);
+  SECURITY_ATTRIBUTES SecurityAttributes;
+  ZeroMemory(&SecurityAttributes, sizeof(SecurityAttributes));
+  SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+  SecurityAttributes.bInheritHandle = TRUE;
+  SecurityAttributes.lpSecurityDescriptor = NULL;
+
+  HANDLE PipeRead = INVALID_HANDLE_VALUE;
+  HANDLE PipeWrite = INVALID_HANDLE_VALUE;
+
+  if (!CreatePipe(&PipeRead, &PipeWrite, &SecurityAttributes, 0) ||
+      !SetHandleInformation(PipeRead, HANDLE_FLAG_INHERIT, 0))
+  {
+    throw EOSExtException(FMTLOAD(EXECUTE_APP_ERROR, (Command)));
+  }
+
+  PROCESS_INFORMATION ProcessInformation;
+  ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
+
+  try
+  {
+    try
+    {
+      STARTUPINFO StartupInfo;
+      ZeroMemory(&StartupInfo, sizeof(StartupInfo));
+      StartupInfo.cb = sizeof(STARTUPINFO);
+      StartupInfo.hStdError = PipeWrite;
+      StartupInfo.hStdOutput = PipeWrite;
+      StartupInfo.wShowWindow = SW_HIDE;
+      StartupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+
+      if (!CreateProcess(NULL, Command.c_str(), NULL, NULL, TRUE, 0, NULL, NULL, &StartupInfo, &ProcessInformation))
+      {
+        throw EOSExtException(FMTLOAD(EXECUTE_APP_ERROR, (Command)));
+      }
+    }
+    __finally
+    {
+      // If we do not close the handle here, the ReadFile below would get stuck once the app finishes writting,
+      // as it still sees that someone "can" write to the pipe.
+      CloseHandle(PipeWrite);
+    }
+
+    char Buffer[4096];
+    DWORD BytesRead;
+    while (ReadFile(PipeRead, Buffer, sizeof(Buffer), &BytesRead, NULL))
+    {
+      Output += UnicodeString(UTF8String(Buffer, BytesRead));
+      // Same as in ExecuteShellCheckedAndWait
+      Sleep(200);
+      Application->ProcessMessages();
+    }
+
+    DWORD ExitCode;
+    if (DebugAlwaysTrue(GetExitCodeProcess(ProcessInformation.hProcess, &ExitCode)) &&
+        (ExitCode != 0))
+    {
+      throw ExtException(MainInstructions(FMTLOAD(COMMAND_FAILED_CODEONLY, (static_cast<int>(ExitCode)))), Output);
+    }
+  }
+  __finally
+  {
+    CloseHandle(ProcessInformation.hProcess);
+    CloseHandle(ProcessInformation.hThread);
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall ExecuteProcessChecked(const UnicodeString & Command, UnicodeString * Output)
+{
+  if (Output == NULL)
+  {
+    ExecuteShellChecked(Command);
+  }
+  else
+  {
+    ExecuteProcessAndReadOutput(Command, *Output);
+  }
+}
+//---------------------------------------------------------------------------
+void __fastcall ExecuteProcessCheckedAndWait(const UnicodeString & Command, UnicodeString * Output)
+{
+  if (Output == NULL)
+  {
+    ExecuteShellCheckedAndWait(Command, &Application->ProcessMessages);
+  }
+  else
+  {
+    ExecuteProcessAndReadOutput(Command, *Output);
+  }
 }
 //---------------------------------------------------------------------------
 bool __fastcall IsKeyPressed(int VirtualKey)

+ 2 - 1
source/windows/Tools.h

@@ -10,7 +10,8 @@
 #include <Vcl.Graphics.hpp>
 //---------------------------------------------------------------------------
 void __fastcall CenterFormOn(TForm * Form, TControl * CenterOn);
-void __fastcall ExecuteShellCheckedAndWait(const UnicodeString Command);
+void __fastcall ExecuteProcessChecked(const UnicodeString & Command, UnicodeString * Output);
+void __fastcall ExecuteProcessCheckedAndWait(const UnicodeString & Command, UnicodeString * Output);
 bool __fastcall IsKeyPressed(int VirtualKey);
 bool __fastcall UseAlternativeFunction();
 bool __fastcall OpenInNewWindow();

+ 4 - 0
source/windows/WinConfiguration.cpp

@@ -2848,6 +2848,10 @@ void __fastcall TCustomCommandType::LoadExtension(TStrings * Lines, const Unicod
             {
               Params |= ccRemoteFiles;
             }
+            else if (SameText(Value, L"ShowResultsInMsgBox"))
+            {
+              Params |= ccShowResultsInMsgBox;
+            }
             else
             {
               throw Exception(MainInstructions(FMTLOAD(EXTENSION_DIRECTIVE_ERROR, (Value, Directive))));