ما هي أفضل طريقة لتحديد إجراء مخصص في WiX؟

StackOverflow https://stackoverflow.com/questions/128279

  •  02-07-2019
  •  | 
  •  

سؤال

انا املك ويكس المثبت وإجراء مخصص واحد (بالإضافة إلى التراجع والتراجع) له والذي يستخدم خاصية من المثبت.يجب أن يحدث الإجراء المخصص بعد أن تكون جميع الملفات موجودة على القرص الثابت.يبدو أنك تحتاج إلى 16 إدخالاً في ملف WXS لهذا الغرض؛ثمانية داخل الجذر، هكذا:

<CustomAction Id="SetForRollbackDo" Execute="immediate" Property="RollbackDo" Value="[MYPROP]"/>
<CustomAction Id="RollbackDo" Execute="rollback" BinaryKey="MyDLL" DllEntry="UndoThing" Return="ignore"/>
<CustomAction Id="SetForDo" Execute="immediate" Property="Do" Value="[MYPROP]"/>
<CustomAction Id="Do" Execute="deferred" BinaryKey="MyDLL" DllEntry="DoThing" Return="check"/>
<CustomAction Id="SetForRollbackUndo" Execute="immediate" Property="RollbackUndo" Value="[MYPROP]"/>
<CustomAction Id="RollbackUndo" Execute="rollback" BinaryKey="MyDLL" DllEntry="DoThing" Return="ignore"/>
<CustomAction Id="SetForUndo" Execute="immediate" Property="Undo" Value="[MYPROP]"/>
<CustomAction Id="Undo" Execute="deferred" BinaryKey="MyDLL" DllEntry="UndoThing" Return="check"/>

وثمانية داخل InstallExecuteSequence, ، مثل ذلك:

<Custom Action="SetForRollbackDo" After="InstallFiles">REMOVE&lt;>"ALL"</Custom>
<Custom Action="RollbackDo" After="SetForRollbackDo">REMOVE&lt;>"ALL"</Custom>
<Custom Action="SetForDo" After="RollbackDo">REMOVE&lt;>"ALL"</Custom>
<Custom Action="Do" After="SetForDo">REMOVE&lt;>"ALL"</Custom>
<Custom Action="SetForRollbackUndo" After="InstallInitialize">REMOVE="ALL"</Custom>
<Custom Action="RollbackUndo" After="SetForRollbackUndo">REMOVE="ALL"</Custom>
<Custom Action="SetForUndo" After="RollbackUndo">REMOVE="ALL"</Custom>
<Custom Action="Undo" After="SetForUndo">REMOVE="ALL"</Custom>

هل هناك طريقة أفضل؟

هل كانت مفيدة؟

المحلول

لقد واجهت نفس المشكلة عند كتابة مثبتات WiX.أسلوبي في التعامل مع المشكلة يشبه في الغالب ما اقترحه مايك ولدي مشاركة على مدونة تنفيذ الإجراءات المخصصة لـ WiX، الجزء 2:باستخدام الجداول المخصصة.

باختصار، يمكنك تحديد جدول مخصص لبياناتك:

<CustomTable Id="LocalGroupPermissionTable">
    <Column Id="GroupName" Category="Text" PrimaryKey="yes" Type="string"/>
    <Column Id="ACL" Category="Text" PrimaryKey="no" Type="string"/>
    <Row>
        <Data Column="GroupName">GroupToCreate</Data>
        <Data Column="ACL">SeIncreaseQuotaPrivilege</Data>
    </Row>
</CustomTable>

ثم اكتب إجراءً مخصصًا فوريًا واحدًا لجدولة الإجراءات المخصصة المؤجلة والتراجع والالتزام:

extern "C" UINT __stdcall ScheduleLocalGroupCreation(MSIHANDLE hInstall)
{
    try {
        ScheduleAction(hInstall,L"SELECT * FROM CreateLocalGroupTable", L"CA.LocalGroupCustomAction.deferred", L"create");
        ScheduleAction(hInstall,L"SELECT * FROM CreateLocalGroupTable", L"CA.LocalGroupCustomAction.rollback", L"create");
    }
    catch( CMsiException & ) {
        return ERROR_INSTALL_FAILURE;
    }
    return ERROR_SUCCESS;
}

يوضح التعليمة البرمجية التالية كيفية جدولة إجراء مخصص واحد.في الأساس، ما عليك سوى فتح الجدول المخصص، وقراءة الخاصية التي تريدها (يمكنك الحصول على مخطط أي جدول مخصص عن طريق الاتصال مسيفيوجيتكولومنينفو ())، ثم قم بتنسيق الخصائص المطلوبة في الملف CustomActionData الملكية (أنا أستخدم النموذج /propname:value, ، على الرغم من أنه يمكنك استخدام أي شيء تريده).

void ScheduleAction(MSIHANDLE hInstall,
            const wchar_t *szQueryString,
            const wchar_t *szCustomActionName,
            const wchar_t *szAction)
{
    CTableView view(hInstall,szQueryString);
    PMSIHANDLE record;

    //For each record in the custom action table
    while( view.Fetch(record) ) {
        //get the "GroupName" property
        wchar_t recordBuf[2048] = {0};
        DWORD    dwBufSize(_countof(recordBuf));
        MsiRecordGetString(record, view.GetPropIdx(L"GroupName"), recordBuf, &dwBufSize);

        //Format two properties "GroupName" and "Operation" into
        //the custom action data string.
        CCustomActionDataUtil formatter;
        formatter.addProp(L"GroupName", recordBuf);
        formatter.addProp(L"Operation", szAction );

        //Set the "CustomActionData" property".
        MsiSetProperty(hInstall,szCustomActionName,formatter.GetCustomActionData());

        //Add the custom action into installation script. Each
        //MsiDoAction adds a distinct custom action into the
        //script, so if we have multiple entries in the custom
        //action table, the deferred custom action will be called
        //multiple times.
        nRet = MsiDoAction(hInstall,szCustomActionName);
    }
}

أما بالنسبة لتنفيذ الإجراءات المخصصة المؤجلة والتراجع والالتزام، فأنا أفضل استخدام وظيفة واحدة فقط واستخدامها مسيجيتمود () لتمييز ما يجب القيام به:

extern "C" UINT __stdcall LocalGroupCustomAction(MSIHANDLE hInstall)
{
    try {
        //Parse the properties from the "CustomActionData" property
        std::map<std::wstring,std::wstring> mapProps;
        {
            wchar_t szBuf[2048]={0};
            DWORD dwBufSize = _countof(szBuf); MsiGetProperty(hInstall,L"CustomActionData",szBuf,&dwBufSize);
            CCustomActionDataUtil::ParseCustomActionData(szBuf,mapProps);
        }

        //Find the "GroupName" and "Operation" property
        std::wstring sGroupName;
        bool bCreate = false;
        std::map<std::wstring,std::wstring>::const_iterator it;
        it = mapProps.find(L"GroupName");
        if( mapProps.end() != it ) sGroupName = it->second;
        it = mapProps.find(L"Operation");
        if( mapProps.end() != it )
            bCreate = wcscmp(it->second.c_str(),L"create") == 0 ? true : false ;

        //Since we know what opeartion to perform, and we know whether it is
        //running rollback, commit or deferred script by MsiGetMode, the
        //implementation is straight forward
        if( MsiGetMode(hInstall,MSIRUNMODE_SCHEDULED) ) {
            if( bCreate )
                CreateLocalGroup(sGroupName.c_str());
            else
                DeleteLocalGroup(sGroupName.c_str());
        }
        else if( MsiGetMode(hInstall,MSIRUNMODE_ROLLBACK) ) {
            if( bCreate )
                DeleteLocalGroup(sGroupName.c_str());
            else
                CreateLocalGroup(sGroupName.c_str());
        }
    }
    catch( CMsiException & ) {
        return ERROR_INSTALL_FAILURE;
    }
    return ERROR_SUCCESS;
}

باستخدام التقنية المذكورة أعلاه، بالنسبة لمجموعة الإجراءات المخصصة النموذجية، يمكنك تقليل جدول الإجراءات المخصصة إلى خمسة إدخالات:

<CustomAction Id="CA.ScheduleLocalGroupCreation"
              Return="check"
              Execute="immediate"
              BinaryKey="CustomActionDLL"
              DllEntry="ScheduleLocalGroupCreation"
              HideTarget="yes"/>
<CustomAction Id="CA.ScheduleLocalGroupDeletion"
              Return="check"
              Execute="immediate"
              BinaryKey="CustomActionDLL"
              DllEntry="ScheduleLocalGroupDeletion"
              HideTarget="yes"/>
<CustomAction Id="CA.LocalGroupCustomAction.deferred"
              Return="check"
              Execute="deferred"
              BinaryKey="CustomActionDLL"
              DllEntry="LocalGroupCustomAction"
              HideTarget="yes"/>
<CustomAction Id="CA.LocalGroupCustomAction.commit"
              Return="check"
              Execute="commit"
              BinaryKey="CustomActionDLL"
              DllEntry="LocalGroupCustomAction"
              HideTarget="yes"/>
<CustomAction Id="CA.LocalGroupCustomAction.rollback"
              Return="check"
              Execute="rollback"
              BinaryKey="CustomActionDLL"
              DllEntry="LocalGroupCustomAction"
              HideTarget="yes"/>

وجدول InstallSquence يحتوي على إدخالين فقط:

<InstallExecuteSequence>
    <Custom Action="CA.ScheduleLocalGroupCreation" 
            After="InstallFiles">
        Not Installed
    </Custom>
    <Custom Action="CA.ScheduleLocalGroupDeletion" 
            After="InstallFiles">
        Installed
    </Custom>
</InstallExecuteSequence>

بالإضافة إلى ذلك، مع القليل من الجهد، يمكن كتابة معظم التعليمات البرمجية لإعادة استخدامها (مثل القراءة من جدول مخصص، والحصول على الخصائص، وتنسيق الخصائص المطلوبة وتعيين خصائص CustomActionData)، وأصبحت الإدخالات في جدول الإجراءات المخصصة الآن ليس تطبيقًا محددًا (يتم كتابة البيانات الخاصة بالتطبيق في الجدول المخصص)، يمكننا وضع جدول الإجراءات المخصصة في ملف خاص به وإدراجه فقط في كل مشروع WiX.

بالنسبة لملف DLL للإجراء المخصص، نظرًا لأن بيانات التطبيق تتم قراءتها من الجدول المخصص، يمكننا الاحتفاظ بالتفاصيل الخاصة بالتطبيق خارج تنفيذ DLL، بحيث يصبح جدول الإجراء المخصص مكتبة وبالتالي يسهل إعادة استخدامه.

هذه هي الطريقة التي أكتب بها حاليًا إجراءات WiX المخصصة الخاصة بي، إذا كان أي شخص يعرف كيفية تحسينها بشكل أكبر سأكون ممتنًا للغاية.:)

(يمكنك أيضًا العثور على كود المصدر الكامل في منشور مدونتي، تنفيذ إجراءات Wix المخصصة، الجزء 2:باستخدام الجداول المخصصة.).

نصائح أخرى

تعد الإجراءات المخصصة لـ WiX نموذجًا رائعًا يجب اتباعه.في هذه الحالة، أنت تعلن فقط، مع CustomAction, والإجراء الفوري، والإجراء المؤجل، وإجراء التراجع.يمكنك جدولة فقط، مع Custom, ، الإجراء الفوري، حيث يتم تنفيذ الإجراء الفوري كرمز في ملف DLL أصلي.

ثم، في الإجراء الفوري شفرة, ، أنت أتصل MsiDoAction لجدولة التراجع والإجراءات المؤجلة:عندما يتم تأجيلها، يتم كتابتها في البرنامج النصي عند النقطة التي تتصل بها MsiDoAction بدلاً من إعدامه على الفور.سوف تحتاج إلى الاتصال MsiSetProperty وكذلك لتعيين بيانات الإجراء المخصص.

قم بتنزيل كود مصدر WiX وادرس كيفية عمل IISExtension يعمل، على سبيل المثال.تقوم إجراءات WiX بشكل عام بتحليل جدول مخصص وإنشاء البيانات الخاصة بخاصية الإجراء المؤجل بناءً على هذا الجدول.

إذا كانت لديك إجراءات مخصصة معقدة تحتاج إلى دعم التراجع، فقد تفكر في كتابة ملحق Wix.توفر الإضافات عادةً دعمًا للتأليف (على سبيل المثال.علامات XML الجديدة التي يتم تعيينها لإدخالات جدول MSI)، بالإضافة إلى الجدولة التلقائية للإجراءات المخصصة.

إنه عمل أكثر من مجرد كتابة إجراء مخصص، ولكن بمجرد وصول المراجع المصدقة الخاصة بك إلى مستوى معين من التعقيد، فإن سهولة التأليف التي توفرها الامتدادات يمكن أن تستحق العناء.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top