使用ShellExecute发送一个shell脚本给sqlite3.exe
Using ShellExecute to send sqlite3.exe a shell script
我已经在文件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自动删除以点开头的行末尾的多余分号。
相关文章:
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 运行同一解决方案的另一个项目的项目
- 挂起和取消挂起一个文件DLL
- 用C++中的一个变量定义一个常量
- 函数向量_指针有不同的原型,我可以构建一个吗
- 如何将我的 cli 信息(变量等)共享到子进程,这是一个 bash shell 脚本
- 分叉:使用一个参数运行 shell 时资源暂时不可用
- 打开一个 Shell 程序,向其传递参数,然后返回结果
- 一个简短的c++文件和makefile:我可以在shell中制作,但在Eclipse中构建它时会遇到很多错误
- 开发一个交互式shell
- 在 Xcode 中创建一个新的"Shell Tool"目标以供使用 Google 测试
- 我该如何编写一个通过从shell运行来编译自己的c++程序
- 如何创建一个将命令行参数传递给shell脚本的c++程序
- Unix中的c++ Shell, execv:从函数动态创建并返回一个可用的第二个参数
- 使用ShellExecute发送一个shell脚本给sqlite3.exe
- 如何使用shell脚本运行一个进程两次
- 为什么我们需要写一个自己的复制程序,而我们可以使用复制shell命令
- 如何在C/ c++中创建一个微shell