Delphi7:如何执行shell命令并检查结果?

Delphi7:如何执行shell命令并检查结果?,delphi,Delphi,我使用的是Delphi7,无法预测Windows的目标版本 我需要创建一个数据库(可能是MySql,但可能是其他的),并定义一些表结构。我不需要填充任何数据。不幸的是,所有ADO组件似乎都希望数据库已经存在,然后它们将允许您操作它 因此,由于这只是几个简单的命令,我认为我最好使用ShellExectute() 同意吗?不同意 有人能给我一个示例代码来尝试运行“MySql--version”并让我检查结果吗?在那之后,我应该能自己弄清楚。谢谢 [编辑] 无意冒犯,但我知道怎么用谷歌搜索。只是我没

我使用的是Delphi7,无法预测Windows的目标版本

我需要创建一个数据库(可能是MySql,但可能是其他的),并定义一些表结构。我不需要填充任何数据。不幸的是,所有ADO组件似乎都希望数据库已经存在,然后它们将允许您操作它

因此,由于这只是几个简单的命令,我认为我最好使用ShellExectute()

同意吗?不同意

有人能给我一个示例代码来尝试运行“MySql--version”并让我检查结果吗?在那之后,我应该能自己弄清楚。谢谢


[编辑]

无意冒犯,但我知道怎么用谷歌搜索。只是我没有找到有用的结果。这是我自己的错误,没有在这个问题上明确,所以请接受我的道歉-我需要的是一个代码示例,而不仅仅是一个组件的名称

抱歉(感谢您的回复(所有回复均为+1))


[编辑]


Robert提供的链接完成了这项工作(过程rundosinemo()完成了这项工作)B U T您必须记住包含一个.exe扩展名(因此,'notepad.exe',而不仅仅是'notepad',并且如果您的命令不在路径上,则要设置一个完整路径。

我想知道为什么每个想要启动新进程的人都倾向于使用ShellExecute,它是为了在相关应用程序中打开文件而设计的

想要新流程吗?然后使用CreateProcess。故事结束


CreateProcess允许您等待进程、获取其退出代码、读取其控制台输出以及更多内容。

下面是一篇详细解释它的文章

但简而言之,您需要创建两个管道来读取和写入输出,然后需要在中设置StdInput和StdOutput,然后将此结构传递给调用


下面是一个演示如何等待进程完成的示例。

您正在寻找的可能是一个嵌入式数据库。一些选项:

  • 火鸟嵌入式
  • 嵌入式MySQL
  • SQLite
使用任一数据库和适当的数据访问组件(不确定嵌入式FB和MySQL是否支持ADO),您将能够:

  • 不带DB的附加
  • 创建数据库
  • 然后创建表

从以下位置使用DSiExecuteAndCapture:


很久以前我从一个新闻组的帖子中保存了这篇文章;不过我不知道是谁写的

这段代码允许您运行DOS应用程序,并在TMemo中捕获它的输出。然后,您可以通过尝试和错误分析这些行,从备忘录中提取您需要的内容

procedure TFMainForm.RunDosInMemo(const DosApp: String; AMemo: TRichEdit);
const
  ReadBuffer = 2400;
var
  Security : TSecurityAttributes;
  StdInPipeR, StdInPipeW : THandle;
  StdOutPipeR, StdOutPipeW : THandle;
  StartInfo : TStartUpInfo;
  ProcessInfo : TProcessInformation;
  Buffer : PByte;
  BytesAvailable, BytesRead : DWord;
  sDosApp: String;
  sData: RawByteString;
begin
  sDosApp := DosApp;
  UniqueString(sDosApp);

  with Security do begin
    nLength := SizeOf(TSecurityAttributes);
    bInheritHandle := True;
    lpSecurityDescriptor := nil;
  end;

  if CreatePipe(StdInPipeR, StdInPipeW, @Security, 0) then
  try

    SetHandleInformation(StdInPipeW, HANDLE_FLAG_INHERIT, 0);
    if CreatePipe(StdOutPipeR, StdOutPipeW, @Security, 0) then
    try
      SetHandleInformation(StdOutPipeR, HANDLE_FLAG_INHERIT, 0);
      GetMem(Buffer, ReadBuffer);
      try
        ZeroMemory(@StartInfo, SizeOf(StartInfo));
        StartInfo.cb := SizeOf(StartInfo);
        StartInfo.hStdOutput := StdOutPipeW;
        StartInfo.hStdInput := StdInPipeR;
        StartInfo.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
        StartInfo.wShowWindow := SW_HIDE;

        if CreateProcess(nil, 
                         PChar(sDosApp), 
                         nil, 
                         nil, 
                         True, 
                         NORMAL_PRIORITY_CLASS, 
                         nil, 
                         nil, 
                         StartInfo, 
                         ProcessInfo) then
          try
            while WaitForSingleObject(ProcessInfo.hProcess, 500) <> WAIT_TIMEOUT do
              Application.ProcessMessages;
            while PeekNamedPipe(StdOutPipeR, nil, 0, nil, BytesAvailable, nil) do 
            begin
              if BytesAvailable < 1 then 
                Break;
              if BytesAvailable > ReadBuffer then 
                BytesAvailable := ReadBuffer;
              if not ReadFile(StdOutPipeR, 
                              Buffer[0], 
                              BytesAvailable, 
                              BytesRead, 
                              nil) then 
                Break;
              SetString(sData, PAnsiChar(Buffer), BytesRead);
              // assign an appropriate codepage for the output data:
              // 0 for default Ansi, 1252 or 20157 for ASCII, 1200 for 
              // Unicode, etc...
              SetCodePage(sData, ...);
              // this is faster and more efficient than reading/writing the 
              // Text property directly...
              AMemo.SelStart := AMemo.GetTextLen;
              AMemo.SelLength := 0;
              AMemo.SelText := sData;
            end;
          finally
            CloseHandle(ProcessInfo.hThread);
            CloseHandle(ProcessInfo.hProcess);
          end;
      finally
        FreeMem(Buffer);
      end;
    finally
      CloseHandle(StdOutPipeR);
      CloseHandle(StdOutPipeW);
    end;
  finally
    CloseHandle(StdInPipeR);
    CloseHandle(StdInPipeW);
  end;
end;
procedure TFMainForm.rundosinemo(const DosApp:String;AMemo:TRichEdit);
常数
ReadBuffer=2400;
变量
安全性:t安全属性;
StdInPipeR,StdInPipeW:THandle;
标准管道,标准管道:坦德尔;
StartInfo:TStartUpInfo;
ProcessInfo:TProcessInformation;
缓冲液:PByte;
字节可用,字节读取:DWord;
sDosApp:字符串;
sData:RawByteString;
开始
sDosApp:=DosApp;
唯一字符串(sDosApp);
从安全开始
nLength:=SizeOf(TSecurityAttributes);
bInheritHandle:=真;
lpSecurityDescriptor:=零;
结束;
如果CreatePipe(StdInPipeR,StdInPipeW,@Security,0),则
尝试
SetHandleInformation(StdInPipeW,HANDLE\u FLAG\u INHERIT,0);
如果CreatePipe(StdOutPipeR,stdoutPipe,@Security,0),则
尝试
SetHandleInformation(StdOutPipeR,句柄\标志\继承,0);
GetMem(Buffer,ReadBuffer);
尝试
零内存(@StartInfo,SizeOf(StartInfo));
StartInfo.cb:=SizeOf(StartInfo);
StartInfo.hst输出:=StdOutPipeW;
StartInfo.hst输入:=StdInPipeR;
StartInfo.dwFlags:=STARTF_USESTDHANDLES或STARTF_USESHOWWINDOW;
StartInfo.wShowWindow:=SW_HIDE;
如果CreateProcess(无,
PChar(sDosApp),
无
无
是的,
正常优先级等级,
无
无
StartInfo,
ProcessInfo)然后
尝试
WaitForSingleObject(ProcessInfo.hProcess,500)等待时超时
Application.ProcessMessages;
而PeekNamedPipe(StdOutPipeR,nil,0,nil,BytesAvailable,nil)可以
开始
如果字节数小于1,则
打破
如果字节可用>读取缓冲区,则
字节可用:=ReadBuffer;
如果不是读取文件(StdOutPipeR,
缓冲区[0],
字节可用,
拜特斯拉德,
零)那么
打破
设置字符串(sData、PAnsiChar(缓冲区)、字节读取);
//为输出数据分配适当的代码页:
//默认Ansi为0,ASCII为1252或20157,默认Ansi为1200
//Unicode等。。。
设置代码页(sData等);
//这比读/写文件更快、更高效
//文本属性直接。。。
AMemo.SelStart:=AMemo.GetTextLen;
AMemo.SelLength:=0;
AMemo.SelText:=sData;
结束;
最后
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hproces);
结束;
最后
FreeMem(缓冲区);
结束;
最后
闭合手柄(标准管道);
关闭手柄(标准管道);
结束;
最后
关闭手柄(标准管道);
关闭手柄(标准管道);
结束;
结束;

很久以前,我在delphi中编写了一个单元和一组组件来处理控制台重定向:

但除此之外,您不必经历这些:仅使用ADO连接组件来连接
procedure TFMainForm.RunDosInMemo(const DosApp: String; AMemo: TRichEdit);
const
  ReadBuffer = 2400;
var
  Security : TSecurityAttributes;
  StdInPipeR, StdInPipeW : THandle;
  StdOutPipeR, StdOutPipeW : THandle;
  StartInfo : TStartUpInfo;
  ProcessInfo : TProcessInformation;
  Buffer : PByte;
  BytesAvailable, BytesRead : DWord;
  sDosApp: String;
  sData: RawByteString;
begin
  sDosApp := DosApp;
  UniqueString(sDosApp);

  with Security do begin
    nLength := SizeOf(TSecurityAttributes);
    bInheritHandle := True;
    lpSecurityDescriptor := nil;
  end;

  if CreatePipe(StdInPipeR, StdInPipeW, @Security, 0) then
  try

    SetHandleInformation(StdInPipeW, HANDLE_FLAG_INHERIT, 0);
    if CreatePipe(StdOutPipeR, StdOutPipeW, @Security, 0) then
    try
      SetHandleInformation(StdOutPipeR, HANDLE_FLAG_INHERIT, 0);
      GetMem(Buffer, ReadBuffer);
      try
        ZeroMemory(@StartInfo, SizeOf(StartInfo));
        StartInfo.cb := SizeOf(StartInfo);
        StartInfo.hStdOutput := StdOutPipeW;
        StartInfo.hStdInput := StdInPipeR;
        StartInfo.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
        StartInfo.wShowWindow := SW_HIDE;

        if CreateProcess(nil, 
                         PChar(sDosApp), 
                         nil, 
                         nil, 
                         True, 
                         NORMAL_PRIORITY_CLASS, 
                         nil, 
                         nil, 
                         StartInfo, 
                         ProcessInfo) then
          try
            while WaitForSingleObject(ProcessInfo.hProcess, 500) <> WAIT_TIMEOUT do
              Application.ProcessMessages;
            while PeekNamedPipe(StdOutPipeR, nil, 0, nil, BytesAvailable, nil) do 
            begin
              if BytesAvailable < 1 then 
                Break;
              if BytesAvailable > ReadBuffer then 
                BytesAvailable := ReadBuffer;
              if not ReadFile(StdOutPipeR, 
                              Buffer[0], 
                              BytesAvailable, 
                              BytesRead, 
                              nil) then 
                Break;
              SetString(sData, PAnsiChar(Buffer), BytesRead);
              // assign an appropriate codepage for the output data:
              // 0 for default Ansi, 1252 or 20157 for ASCII, 1200 for 
              // Unicode, etc...
              SetCodePage(sData, ...);
              // this is faster and more efficient than reading/writing the 
              // Text property directly...
              AMemo.SelStart := AMemo.GetTextLen;
              AMemo.SelLength := 0;
              AMemo.SelText := sData;
            end;
          finally
            CloseHandle(ProcessInfo.hThread);
            CloseHandle(ProcessInfo.hProcess);
          end;
      finally
        FreeMem(Buffer);
      end;
    finally
      CloseHandle(StdOutPipeR);
      CloseHandle(StdOutPipeW);
    end;
  finally
    CloseHandle(StdInPipeR);
    CloseHandle(StdInPipeW);
  end;
end;