如何从Inno Setup通知Python环境路径已经改变?

时间:2013-03-20 20:15:02

标签: python-2.7 installer inno-setup pascal

所以我正在尝试创建一个包含以下步骤的安装程序:

  1. 检查是否已安装Python
  2. 复制我的应用文件
  3. 检查Python安装目录是否在Windows环境路径
  4. 检查Python脚本文件夹是否在Windows环境路径
  5. 如果脚本文件夹不在env路径中,请添加
  6. 安装easy_install
  7. 运行一个使用easy_install安装多个库的python脚本
  8. 在最后几个步骤中遇到了问题。以下是我目前正在使用的Inno设置的相关代码:

    begin
      case CurStep of
         ssInstall:       // File transfer is about to begin.
         begin
            // Note: Use abort(); to terminate the install during this step.
         end;
    
    ssPostInstall:   // File transfer has finished.
      begin
         // Make sure Python is in the path.
         sPythonInstallDir := _PythonGetInstallDir();
         _PathAddToSystem( sPythonInstallDir )
         _PathAddToSystem( sPythonInstallDir + 'Scripts;' )
    
         // Run the bundled Python script.
         ExtractTemporaryFile( 'build_setup_script.py' );
         ExtractTemporaryFile( 'ez_setup.py'           );
         _LaunchApp( AddQuotes( sPythonInstallDir + 'python.exe' ), AddQuotes( ExpandConstant( '{tmp}\build_setup_script.py' ) ), ExpandConstant( '{tmp}' ), SW_SHOW, ewWaitUntilTerminated, 300, nTime, nResultCode );
      end;
    
    ssDone :         // After the Finish dialog.
      begin
      end;
    end;
    

    这是python脚本:

    def main(argv):
       ## Easy Install
       print("Installing easy_install")
       call(["Python", "ez_setup.py"])
    ...
       ## Installs server.py dependencies
       print("\nInstalling SQLAlchemy")
       call(["easy_install", "SQLAlchemy==0.7.8"])
    ...
    

    在inno设置中,我也有以下指令

    [Setup]
    ...
    ChangesEnvironment=true
    ...   
    

    但是,根据此post,该指令仅在用户单击“完成”后生效。

    因此设置会附加到路径:

    ...C:\Program Files (x86)\Git\cmd;;C:\Python27\;C:\Python27\Scripts;
    

    但是,然后脚本运行(因为inno似乎意识到路径已经改变并且可以执行Python文件),然后脚本将安装easy_install,这可以出于某种原因,但是当它尝试使用easy_install时(这就是为什么C:Python \ Scripts;在路径中)它抛出一个未找到文件的异常。

    但是,当我第二次运行安装程序而不进行任何更改时,easy_install步骤将会起作用,因为现在当Python运行时,它可以检测到easy_install的路径。

    我认为必须有一种方法可以在单击完成之前通知进程,但是复制上述post中的代码甚至无法在inno中编译

    SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0, LPARAM(PChar('Environment')), SMTO_ABORTIFHUNG, 5000, MsgResult);
    

    要求用户第二次开始安装是不可能的,因为安装程序应该首先自动化......任何想法?

1 个答案:

答案 0 :(得分:2)

如果要通知所有窗口有关环境更改,请执行以下代码(向导完成时InnoSetup内部使用,ChangesEnvironment指令设置为yes):

SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
  LPARAM(PChar('Environment')), SMTO_ABORTIFHUNG, 5000, MsgResult);

您可以使用以下导入(使用最新的ANSI和Unicode版本的InnoSetup进行测试):

[Code]
#ifdef UNICODE
  #define AW "W"
#else
  #define AW "A"
#endif
const
  SMTO_ABORTIFHUNG = 2;
  WM_WININICHANGE = $001A;
  WM_SETTINGCHANGE = WM_WININICHANGE;
type
  LONG_PTR = LongInt;
  LRESULT = LONG_PTR;  
  WPARAM = UINT_PTR;
  LPARAM = LONG_PTR;

function SendTextMessageTimeout(hWnd: HWND; Msg: UINT;
  wParam: WPARAM; lParam: string; fuFlags: UINT; 
  uTimeout: UINT; var lpdwResult: DWORD_PTR): LRESULT;
  external 'SendMessageTimeout{#AW}@user32.dll stdcall';

并在脚本中随时调用此伪代码中显示的内容:

var
  MsgResult: DWORD_PTR;
begin
  if SendTextMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
    'Environment', SMTO_ABORTIFHUNG, 5000, MsgResult) <> 0
  then
    MsgBox('Success!', mbInformation, MB_OK)
  else
    MsgBox(SysErrorMessage(DLLGetLastError), mbError, MB_OK);
end;