使用ShellExecute发送一个shell脚本给sqlite3.exe

Using ShellExecute to send sqlite3.exe a shell script

本文关键字:shell 一个 脚本 exe sqlite3 ShellExecute 使用      更新时间:2023-10-16

我已经在文件c:/SQLiteData/cmd .txt中获得了以下shell脚本

.open c:/SQLiteData/LGMeta.db
create table Temp {f INTEGER primary key};
insert into Temp values(-1);
.output c:/SQLiteData/Out.txt
select * from Temp;

我尝试使用

在c++程序中运行它
ShellExecute(NULL, L"open", L"c:/SQLiteData/sqlite3.exe",
L".read c:/SQLiteData/Cmnds.txt", NULL, 0);

ShellExecute返回42,表示成功,但什么也没发生。Temp和Out.txt都不会被创建。有人能告诉我我错过了什么吗?

编辑

谢谢你的回复。过去的三天我都被这玩意儿弄得心烦意乱。我从关于

这个主题的几篇文章中把这些拼凑在一起。
unsigned int RunCmnd(String CmndLine)
{
    STARTUPINFO StartupInfo;
    PROCESS_INFORMATION ProcessInfo;
    memset(&ProcessInfo,0,sizeof(ProcessInfo)); // setup memory blocks
    memset(&StartupInfo,0,sizeof(StartupInfo));
    StartupInfo.cb=sizeof(StartupInfo); // set structure size
    StartupInfo.wShowWindow=SW_HIDE; // hide window
    if (CreateProcess(NULL,CmndLine.c_str(),
    NULL,NULL,false,0,NULL,NULL,&StartupInfo,&ProcessInfo))
    {
        WaitForSingleObject(ProcessInfo.hThread,INFINITE);
        return 0;
    }
    else return GetLastError();
}

如果我启动命令shell并输入以下行

c:/SQLiteData/sqlite3.exe < c:/SQLiteData/Cmnds.txt

一切正常,但如果使用

RunCmnd("c:/SQLiteData/sqlite3.exe < c:/SQLiteData/Cmnds.txt")

从我的c++构建器应用程序没有发生任何事情。我遗漏了一些基本的东西。谁能告诉我是什么?

最后我想出了这个,这是改编自TarmoPikaro在这个线程上的一个优秀的帖子如何在c++中使用POSIX执行命令并获得命令的输出?

String TempFileName(bool ForwardSlash) // ForwardSlash default = true
{
    wchar_t Nm[MAX_PATH],Path[MAX_PATH];
    GetTempPath(MAX_PATH,Path);
    if (!GetTempFileName(Path,L"",0,Nm))
        throw Exception(String("TempFileName failed - ")+
        SysErrorMessage(GetLastError()));
    String Name=Nm;
    if (ForwardSlash)
        for (int Len=Name.Length(),i=1; i<=Len; i++) if (Name[i]=='') Name[i]='/';
    return Name;
}
//---------------------------------------------------------------------------
String SQLiteExe(String DB,String OutFile,String Cmds)
{
    // Returns first error message if process doesn't execute cleanly. Otherwise
    // if OutFile=="" it returns the output
    // if Outfile>"" the output is sent to OutFile and return is NULL.
    String Output;
    HANDLE hPipeRead,hPipeWrite;
    SECURITY_ATTRIBUTES saAttr={sizeof(SECURITY_ATTRIBUTES)};
    saAttr.bInheritHandle=TRUE; //Pipe handles are inherited by child process.
    saAttr.lpSecurityDescriptor=NULL;
    // Create a pipe to get output from child's stdout.
    if (!CreatePipe(&hPipeRead,&hPipeWrite,&saAttr,0))
        return "Error: Unable to create pipe";
    STARTUPINFO si={sizeof(STARTUPINFO)};
    si.dwFlags=STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    si.hStdOutput=hPipeWrite;
    si.hStdError=hPipeWrite;
    si.wShowWindow=SW_HIDE;
    // Prevents cmd window from flashing. Requires STARTF_USESHOWWINDOW in dwFlags.
    TStringList *Batch=new TStringList;
    Batch->StrictDelimiter=true;
    Batch->Delimiter=';';
    Batch->DelimitedText=Cmds;
    if (OutFile>"") Batch->Insert(0,".output "+OutFile);
    String S;
    for (int i=0; i<Batch->Count; i++)
    {
        Batch->Strings[i]=Batch->Strings[i].Trim();
        // .commands must have dot as first char on line
        if (Batch->Strings[i]=="") continue;
        S+=Batch->Strings[i]+(Batch->Strings[i][1]=='.' ? "" : ";")+"rn";
    }
    Batch->Text=S;
    String BatchFile=TempFileName();
    Batch->SaveToFile(BatchFile);
    delete Batch;
    String Cmd="sqlite3 "+DB+" ".read "+BatchFile+"""; // assumes sqlite3.exe in PATH
    PROCESS_INFORMATION pi={0};
    BOOL fSuccess=CreateProcessW(NULL,Cmd.c_str(),NULL,NULL,TRUE,CREATE_NEW_CONSOLE,
    NULL,NULL, &si, &pi);
    if (! fSuccess)
    {
        CloseHandle(hPipeWrite);
        CloseHandle(hPipeRead);
        DeleteFile(BatchFile);
        return "Error: Failed to create process";
    }
    bool bProcessEnded=false;
    while (!bProcessEnded)
    {
        // Give some timeslice (50ms), so we won't waste 100% cpu.
        bProcessEnded=WaitForSingleObject(pi.hProcess,50)==WAIT_OBJECT_0;
        // Even if process exited - we continue reading, if there is some data available
        // over pipe.
        while (true)
        {
            char buf[1024];
            DWORD dwRead=0;
            DWORD dwAvail=0;
            if (!::PeekNamedPipe(hPipeRead,NULL,0,NULL,&dwAvail,NULL)) break;
            if (!dwAvail) break; // no data available, return
            if (!::ReadFile(hPipeRead,buf,std::min(sizeof(buf)-1,
            (unsigned int)(dwAvail)),&dwRead,NULL) || !dwRead)
                break; // error, the child process might ended
            buf[dwRead]=0;
            Output+=buf;
        }
        int p=Output.Pos("Error:"); // if (p) return first error  message
        if (p) {Output.Delete(1,p-1); Output.Delete(Output.Pos("rn"),Output.Length());}
    }
    DeleteFile(BatchFile); // NB can't be deleted until ProcessEnded
    CloseHandle(hPipeWrite);
    CloseHandle(hPipeRead);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    return Output;
}
//---------------------------------------------------------------------------
Usage
String Err=SQLiteExe("c:/SQLiteData/MyDB.db","c:/SQLiteData/MyTblDump.txt"",
".mode csv; select * from MyTbl;");
if (Err>"") throw Exception(Err);
else ........

多个命令之间用分号分隔。SQLiteExe自动删除以点开头的行末尾的多余分号。