Inno Setup CreateProcess Winapi调用错误:无法转换为OleStr

时间:2014-07-30 15:37:32

标签: inno-setup pascal createprocess

我写了一个小安装程序,我想写下这里写的东西:Waiting for grandchild processes in windows (我想等到另一个卸载程序完成)

我定义了必要的类型和std调用。

这是我的代码:

procedure UninstallPreviousVersion;
  var
    UninstallString: String;
    ErrorCode: Integer;

    UninstallJob : THandle;
    UninstallStartUpInfo : LPSTARTUPINFO;
    UninstallProcessInfo : LPPROCESS_INFORMATION;

begin

  UninstallJob := CreateJobObject( '' , '' );

  CreateProcess(
    '',
    'C:\Program Files (x86)\InstallShield Installation Information\{2FEAF140-139A-11D5-8925-0050DAE02BFF}\Setup.exe',
    null, 
    null,
    false,
    4,  //CREATE_SUSPENDED 0x00000004
    null, 
    null,
    UninstallStartUpInfo,
    UninstallProcessInfo
  );

  AssignProcessToJobObject( UninstallJob , UninstallProcessInfo.hProcess );
  ResumeThread( UninstallProcessInfo.hThread );
  WaitForSingleObject( UninstallJob , $FFFFFFFF );

  MsgBox('Uninstall returned! Wohohohooo yeah!', mbInformation, MB_OK);

end; 

它编译,并根据调试器在CreateProcess函数期间失败。当我运行安装程序时出现以下错误:     无法将类型(Null)的变体转换为类型(OleStr)。

定义的类型:

type
  LPSTARTUPINFO = record
  cb : DWORD;
  lpReserved : String; 
  lpDesktop : String;  
  lpTitle : String;                                                                    
  dwX:DWORD;
  dwY:DWORD;
  dwXSize:DWORD;
  dwYSize:DWORD;
  dwXCountChars : DWORD;
  dwYCountChars : DWORD;
  dwFillAttribute : DWORD;
  dwFlags : DWORD;
  wShowWindow : WORD;
  cbReserved2 : WORD;
  lpReserved2 : BYTE;
  hStdInput : Thandle;
  hStdOutput : Thandle;
  hStdError : Thandle;
end;

type
  LPPROCESS_INFORMATION  = record
  hProcess:THandle;
  hThread:THandle;
  dwProcessId:DWORD;
  dwThreadId:DWORD;
end;

如有必要,我可以上传更多类型。

修改

此版本编译并启动所需的.exe。 编译器:Inno Setup 5.5 类型未定义,您必须自己定义!在windows dev网站上查找它们。 (上面有两个例子)。

procedure UninstallPreviousVersion;
  var
    UninstallString: String;
    ErrorCode: Integer;

    UninstallJob : THandle;
    UninstallStartUpInfo : LPSTARTUPINFO;
    UninstallProcessInfo : LPPROCESS_INFORMATION;

    Info : LPVOID;
    procAtt : LPSECURITY_ATTRIBUTES;
    threadAtt : LPSECURITY_ATTRIBUTES;
begin

  UninstallStartUpInfo.lpReserved := '';
  UninstallStartUpInfo.lpDesktop := '';
  UninstallStartUpInfo.lpTitle := '';
  UninstallStartUpInfo.dwX := 0;
  UninstallStartUpInfo.dwY := 0;
  UninstallStartUpInfo.dwXSize := 0;
  UninstallStartUpInfo.dwYSize := 0;
  UninstallStartUpInfo.dwXCountChars := 0;
  UninstallStartUpInfo.dwYCountChars := 0;
  UninstallStartUpInfo.dwFillAttribute := 0;
  UninstallStartUpInfo.dwFlags := ( $00000001 ) or ( $00000200 );    //STARTF_USESHOWWINDOW
  UninstallStartUpInfo.wShowWindow := SW_SHOW;
  UninstallStartUpInfo.cbReserved2 := 0;
  UninstallStartUpInfo.lpReserved2 := 0;
  UninstallStartUpInfo.cb := sizeof(UninstallStartUpInfo);

  UninstallJob := CreateJobObject( '' , '' );

  CreateProcess(
    'C:\Program Files (x86)\\InstallShield Installation Information\{2FEAF140-139A-11D5-8925-0050DAE02BFF}\Setup.exe',
    'UNINSTALL',
    procAtt, 
    threadAtt,
    false,
    4,  //CREATE_SUSPENDED 0x00000004
    Info, 
    '',
    UninstallStartUpInfo,
    UninstallProcessInfo
  );

  AssignProcessToJobObject( UninstallJob , UninstallProcessInfo.hProcess );
  ResumeThread( UninstallProcessInfo.hThread );
  WaitForSingleObject( UninstallJob , $FFFFFFFF );  

end;

1 个答案:

答案 0 :(得分:3)

您的代码中存在多个问题。

首先,除了引用NULL类型时,Pascal(包括Inno Setup的Pascal脚本)不使用Variant。将null的使用转换为调用nil中的CreateProcess,开始。

CreateProcess(
  '',
  'C:\Program Files (x86)\InstallShield Installation Information\{2FEAF140-139A-11D5-8925-0050DAE02BFF}\Setup.exe',
  nil, 
  nil,
  false,
  4,  //CREATE_SUSPENDED 0x00000004
  nil, 
  nil,
  UninstallStartUpInfo,
  UninstallProcessInfo
);

接下来,您需要在CreateProcess调用中使用它之前填充lpStartupInfo参数,因为它在STARTUPINFO结构的文档中解释(记录,以Pascal语言表示),从初始化开始它为空值并将cb成员设置为结构的大小。

var
  si: UninstallStartupInfo;
  pi: UninstallProcessInfo;
begin
  FillChar(si, sizeof(si), 0);
  FillChar(pi, sizeof(pi), 0);
  si.cb := sizeof(si);
  si.dwFlags := STARTF_USESHOWWINDOW;
  si.wShowWindow := SW_HIDE;
  if not CreateProcess(...) then
    // Use GetLastError() here to find out why it failed.

最后,您还应该检查返回值; CreateProcess文档告诉您对成功的期望,以及如果它没有返回成功代码该怎么办。

(并且,作为一个注释:InnoSetup的Pascal脚本有一个内置的包装器,用于执行外部文件ShellExec,它有一个参数,告诉它在返回之前等待进程执行。使用它可以使您更容易,除非有特定原因它不能满足您的需求。)

相关问题