문제

기본 MSI 프로젝트가 있습니다.현재 기본 애플리케이션에 통합되어 있는 다른 MSI 제품을 설치 시 제거해야 합니다.업그레이드 시나리오를 활용해 메이저 업그레이드처럼 다루려고 노력했습니다.그러나 업그레이드 코드가 일치하지 않아 작동하지 않았습니다.

다음으로, CostFinalize 이후에 msiexec.exe를 실행하는 사용자 지정 작업도 만들었습니다. (이 내용은 Installshield 도움말에 나와 있는 것 같습니다.) 제거하려는 설치 프로그램이 없는 시스템에 설치하기 전까지는 완벽하게 작동했습니다.더 이상 사용되지 않는 다른 제품이 설치되지 않으면 설치 프로그램이 실패합니다.시스템 검색으로 설정한 커스텀 액션에 조건을 넣어보려고 했는데, 시스템 검색 기능이 제한되어 있는 것 같습니다.등록 키를 확인하고 부울 속성을 설정할 수는 없습니다.

어떤 아이디어가 있나요?

도움이 되었습니까?

해결책

고려해야 할 몇 가지 사항

1) UpgradeTable( FindRelatedProducts / RemoveExisting Products )을 사용하여 다른 제품의 UpgradeCode와 연결된 ProductCode를 제거할 수 있습니다.

2) 메모리가 제공되는 경우 MSI는 컴퓨터별 설치 중에 사용자별 제품을 제거하지 않습니다(또는 그 반대).맥락이 동일해야 합니다.

3) 자동 설치 중에는 UI 시퀀스가 ​​실행되지 않습니다.

4) 시스템당 실행 시퀀스가 ​​하나만 있는 시스템 전체 뮤텍스가 있으므로 실행 시퀀스에서 msiexec를 실행할 수 없습니다.

5) UI에서 예약하는 경우(자동 설치 중에는 실행되지 않으므로 그렇게 하면 안 된다고 이미 말씀드렸습니다) 프로세스당 UI가 1개만 있다는 또 다른 뮤텍스가 있습니다.

사용자별에서 사용자별으로 또는 컴퓨터별에서 컴퓨터별로 이동하는 경우 사용자 지정 작업을 작성하지 않고도 요소/테이블 행 업그레이드를 사용하여 원하는 작업을 수행할 수 있어야 하는 것이 합리적이라고 생각합니다.그렇지 않으면 msiexec 세계에 들어가기 전에 제거를 처리하기 위해 setup.exe 스타일 부트스트래퍼가 필요합니다.

다른 팁

Custom InstallScript를 사용하여 InstallShield 2013에서 이것을 달성했습니다. 스크립트는 UI 시퀀스의 사용자 정의 작업을 통해 실행되지만 "SetupProgress"대화 상자 (즉, 문서가 말하는 것처럼) 대신 "ACTION 실행"이전에 "SETUPPROGRESS"대화 상자 이후에 배치되었습니다. 조건을 동작에 "설치되지 않았다"는 조건을 추가했습니다. 이것을 제안 된 순서로 배치하면 설치 프로그램이 초기화 되 자마자 제거가 시작됩니다. 내가 한 곳으로 이동하면 사용자가 최종 설치 버튼을 클릭 할 때까지 시작되지 않습니다.

이것을 UI 시퀀스에 넣는 이유는 한 번에 한 번의 MSI 설치 프로그램 (또는 설치자)을 가져 오기 때문입니다. 이것은 그 제한으로 인해 실행 시퀀스에서 작동하지 않습니다.

이 방법의 주요 약점은 Christopher가 말했듯이, 이것은 침묵하는 설치에서 작동하지 않는다는 것입니다 (IS 문서에서도 볼 수 있음). 이것이 바로 이것을 달성하기위한 공식적인 수단입니다. (체크 아웃 : http://helpnet.installshield.com/installshield16helplib/ihelpcustomactionmsiexec.htm) 그와 함께 살 수 있다면 (Silent Install은 일반적으로 특별한 경우 시나리오이기 때문에) 이것은 잘 작동합니다.

Chris가 말했듯이, 기본 UI가 실행중인 동안 Unstaller UI를 시작할 수는 없지만 UI없이 UNSTALLER를 실행하기 위해 명령 줄 스위치를 추가하기 때문에 내 스크립트에 문제가되지 않습니다 (즉, 조용히).

내 스크립트는 또한 제거하려는 응용 프로그램의 안내를 알 필요가 없습니다. 다음은 사용자 정의 작업에 바인딩하는 스크립트입니다 (UntallPriorversions는 진입 점 함수입니다).

////////////////////////////////////////////////////////////////////////////////
    //                                                                            
    //  This template script provides the code necessary to build an entry-point 
    //  function to be called in an InstallScript custom action. 
    //                                                                            
    //                                                                            
    //    File Name:  Setup.rul                                                   
    //                                                                            
    //  Description:  InstallShield script                                        
    //
    ////////////////////////////////////////////////////////////////////////////////

    // Include Ifx.h for built-in InstallScript function prototypes, for Windows 
    // Installer API function prototypes and constants, and to declare code for 
    // the OnBegin and OnEnd events.
    #include "ifx.h"

    // The keyword export identifies MyFunction() as an entry-point function.
    // The argument it accepts must be a handle to the Installer database.

    export prototype UninstallPriorVersions(HWND);

    // To Do:  Declare global variables, define constants, and prototype user-
    //         defined and DLL functions here.

    prototype NUMBER UninstallApplicationByName( STRING );
    prototype NUMBER GetUninstallCmdLine( STRING, BOOL, BYREF STRING );
    prototype STRING GetUninstallKey( STRING );
    prototype NUMBER RegDBGetSubKeyNameContainingValue( NUMBER, STRING, STRING, STRING, BYREF STRING );

    // To Do:  Create a custom action for this entry-point function:
    // 1.  Right-click on "Custom Actions" in the Sequences/Actions view.
    // 2.  Select "Custom Action Wizard" from the context menu.
    // 3.  Proceed through the wizard and give the custom action a unique name.
    // 4.  Select "Run InstallScript code" for the custom action type, and in
    //     the next panel select "MyFunction" (or the new name of the entry-
    //     point function) for the source.
    // 5.  Click Next, accepting the default selections until the wizard
    //     creates the custom action.
    //
    // Once you have made a custom action, you must execute it in your setup by
    // inserting it into a sequence or making it the result of a dialog's
    // control event.


    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           
    // Function:  UninstallPriorVersions
    //                                                                           
    //  Purpose:  Uninstall prior versions of this application
    //                                                                           
    ///////////////////////////////////////////////////////////////////////////////
    function UninstallPriorVersions(hMSI)
    begin

        UninstallApplicationByName( "The Name Of Some App" );           

    end;


    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           
    // Function: UninstallApplicationByName
    //                                                                           
    // Purpose: Uninstall an application (without knowing the guid)
    //                        
    // Returns: (UninstCmdLine is assigned a value by referrence)
    //      >= ISERR_SUCCESS    The function successfully got the command line.
    //      < ISERR_SUCCESS     The function failed to get the command line.
    //
    ///////////////////////////////////////////////////////////////////////////////
    function NUMBER UninstallApplicationByName( AppName )
        NUMBER nReturn;
        STRING UninstCmdLine;
    begin           

        nReturn = GetUninstallCmdLine( AppName, TRUE, UninstCmdLine );  
        if( nReturn < ISERR_SUCCESS ) then
            return nReturn;
        endif;

        if( LaunchAppAndWait( "", UninstCmdLine, LAAW_OPTION_WAIT) = 0 ) then 
            return ISERR_SUCCESS;
        else
            return ISERR_SUCCESS-1;
        endif; 

    end;


    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           
    // Function: GetUninstallCmdLine 
    //                                                                           
    // Purpose: Get the command line statement to uninstall an application 
    //                        
    // Returns: (UninstCmdLine is assigned a value by referrence)
    //      >= ISERR_SUCCESS    The function successfully got the command line.
    //      < ISERR_SUCCESS     The function failed to get the command line.
    //
    ///////////////////////////////////////////////////////////////////////////////
    function NUMBER GetUninstallCmdLine( AppName, Silent, UninstCmdLine )
        NUMBER nReturn;
    begin           

        nReturn = RegDBGetUninstCmdLine ( GetUninstallKey( AppName ), UninstCmdLine );
        if( nReturn < ISERR_SUCCESS ) then
            return nReturn;
        endif;

        if( Silent && StrFind( UninstCmdLine, "MsiExec.exe" ) >= 0 )then
            UninstCmdLine = UninstCmdLine + " /qn"; 
        endif; 

        return nReturn;
    end;


    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           
    // Function: GetUninstallKey
    //                                                                           
    // Purpose:  Find the uninstall key in the registry for an application looked up by name
    //      
    // Returns: The uninstall key (i.e. the guid or a fall back value)
    //                                                                       
    ///////////////////////////////////////////////////////////////////////////////
    function STRING GetUninstallKey( AppName )
        STRING guid;
        STRING Key64, Key32, ValueName;
    begin

        Key64 = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
        Key32 = "SOFTWARE\\Wow6432Node\\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; 
        ValueName = "DisplayName";

        if( RegDBGetSubKeyNameContainingValue( HKEY_LOCAL_MACHINE, Key64, ValueName, AppName, guid ) = 0 ) then
            return guid; // return 64 bit GUID
        endif;

        if( RegDBGetSubKeyNameContainingValue( HKEY_LOCAL_MACHINE, Key32, ValueName, AppName, guid ) = 0 ) then
            return guid; // return 32 bit GUID
        endif;

        return AppName; // return old style uninstall key (fall back value)

    end;


    ///////////////////////////////////////////////////////////////////////////////
    //                                                                           
    // Function: RegDBGetSubKeyNameContainingValue
    //                                                                           
    // Purpose:  Find a registry sub key containing a given value.
    //           Return the NAME of the subkey (NOT the entire key path)
    //
    // Returns: (SubKeyName is assigned a value by referrence)
    //      = 0     A sub key name was found with a matching value
    //      != 0    Failed to find a sub key with a matching value
    //                                                                           
    ///////////////////////////////////////////////////////////////////////////////
    function NUMBER RegDBGetSubKeyNameContainingValue( nRootKey, Key, ValueName, Value, SubKeyName )
        STRING SearchSubKey, SubKey, svValue;
        NUMBER nResult, nType, nvSize;
        LIST   listSubKeys;
    begin

        SubKeyName = "";

        listSubKeys  = ListCreate(STRINGLIST);
        if (listSubKeys = LIST_NULL) then
            MessageBox ("Unable to create necessary list.", SEVERE);
            abort;
        endif;

        RegDBSetDefaultRoot( nRootKey );

        if (RegDBQueryKey( Key, REGDB_KEYS, listSubKeys ) = 0) then    
            nResult = ListGetFirstString (listSubKeys, SubKey); 
            while (nResult != END_OF_LIST) 
                SearchSubKey = Key + "\\" + SubKey;
                nType = REGDB_STRING;
                if (RegDBGetKeyValueEx (SearchSubKey, ValueName, nType, svValue, nvSize) = 0) then
                    if( svValue = Value ) then              
                        SubKeyName = SubKey;     
                        nResult = END_OF_LIST;
                    endif;
                endif;      
                if( nResult != END_OF_LIST ) then                       
                    nResult = ListGetNextString (listSubKeys, SubKey); 
                endif;
            endwhile; 
        endif;

        ListDestroy (listSubKeys );

        if ( SubKeyName = "" ) then
            return 1;
        else
            return 0;
        endif;

    end;
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top