我在一个线程中使用此代码(通过Indy Onexecute事件)。有什么问题吗?
function TFrmMain.ShellExecute_AndWait(FileName, Params: string): bool;
var
exInfo: TShellExecuteInfo;
Ph: DWORD;
begin
FillChar(exInfo, SizeOf(exInfo), 0);
with exInfo do
begin
cbSize := SizeOf(exInfo);
fMask := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_FLAG_DDEWAIT;
Wnd := GetActiveWindow();
exInfo.lpVerb := 'open';
exInfo.lpParameters := PChar(Params);
lpFile := PChar(FileName);
nShow := SW_NORMAL;
end;
if ShellExecuteEx(@exInfo) then
Ph := exInfo.hProcess
else
begin
Result := true;
exit;
end;
while WaitForSingleObject(exInfo.hProcess, 50) <> WAIT_OBJECT_0 do
begin
end;
CloseHandle(Ph);
Result := true;
end;
答案 0 :(得分:8)
MSDN有这样的建议:
由于ShellExecuteEx可以将执行委托给使用组件对象模型(COM)激活的Shell扩展(数据源,上下文菜单处理程序,动词实现),因此应在调用ShellExecuteEx之前初始化COM。某些Shell扩展需要COM单线程单元(STA)类型。在这种情况下,COM应该初始化,如下所示:
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)
有些情况下ShellExecuteEx不使用这些类型的Shell扩展之一,并且这些实例根本不需要初始化COM。尽管如此,在使用此功能之前始终将COM初始化是一种好习惯。
(在Delphi中,您当然会用nil
替换第一个参数,并使用or
进行按位操作。)
Raymond Chen最近撰写了关于the consequences of getting this wrong的文章。具体示例是函数可能会因Error_Access_Denied
错误代码而失败。
这是我在代码中看到的唯一潜在的多线程问题。下面是我阅读你的代码时发生的更多事情,虽然它们与多线程无关(而且与Indy没什么关系)。
您有一种特殊的方式等待程序停止运行。你一次反复等待50毫秒,但如果这个过程还没有完成,你什么都不做,只能再等一下。通过为超时指定Infinite
来更准确地描述您的意图。
该函数始终返回True
。如果没有有用的返回值,那么你应该把它作为一个程序,这样根本就没有返回值。不要将呼叫者与无用的信息混淆。如果您要将其保留为函数,则使用Delphi本机类型Boolean
而不是Windows兼容性类型Bool
作为返回类型。
我对服务器在收到网络消息时执行用户交互程序的想法有点担心。
注意MSDN说你可能没有得到进程句柄。有些情况ShellExecuteEx
可以在不创建新流程的情况下为您的请求提供服务,因此您无需等待。
用户可能会在一段时间内使用该程序,并且您的服务器将一直等待等待。我想知道它是否真的需要等待。客户端是否也在等待服务器的响应?