2008-09-24 14 views
13

मेरे पास WiX इंस्टॉलर है और इसके लिए एक कस्टम एक्शन (प्लस पूर्ववत और रोलबैक) है जो इंस्टॉलर से एक संपत्ति का उपयोग करता है। सभी फ़ाइलों को हार्ड डिस्क पर होने के बाद कस्टम कार्रवाई होनी चाहिए। ऐसा लगता है कि इसके लिए आपको WXS फ़ाइल में 16 प्रविष्टियों की आवश्यकता है; आठ जड़ के भीतर है, इसलिए जैसे:वाईएक्स में कस्टम एक्शन को कैसे परिभाषित किया जाए?

<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> 

वहाँ एक बेहतर तरीका है?

उत्तर

2

वाईएक्स इंस्टॉलर्स लिखते समय मुझे एक ही समस्या आई। समस्या का मेरा दृष्टिकोण ज्यादातर माइक ने सुझाव दिया है और मेरे पास ब्लॉग पोस्ट Implementing WiX custom actions part 2: using custom tables है।

संक्षेप में, आप अपने डेटा के लिए एक कस्टम तालिका को परिभाषित कर सकते हैं:

<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; 
} 

निम्न कोड दिखाता है कि एक कस्टम कार्रवाई को शेड्यूल कैसे करें। असल में आप केवल कस्टम टेबल खोलते हैं, अपनी इच्छित संपत्ति को पढ़ते हैं (आप MsiViewGetColumnInfo() पर कॉल करके किसी भी कस्टम तालिका की स्कीमा प्राप्त कर सकते हैं), फिर कस्टमएक्शनडाटा प्रॉपर्टी में आवश्यक गुणों को प्रारूपित करें (मैं फॉर्म /propname:value का उपयोग करता हूं, हालांकि आप जो कुछ भी चाहते हैं उसका उपयोग कर सकते हैं)।

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; 
} 

का उपयोग करके:

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); 
    } 
} 

आस्थगित, रोलबैक को लागू करने और कस्टम कार्यों के लिए प्रतिबद्ध के लिए के रूप में, मैं अलग करने के लिए क्या किया जाना चाहिए केवल एक ही समारोह का उपयोग करें और MsiGetMode()का उपयोग करना पसंद तकनीक के ऊपर, एक सामान्य कस्टम एक्शन सेट के लिए आप कस्टम एक्शन टेबल को पांच प्रविष्टियों में कम कर सकते हैं:

<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"/> 

और इंस्टॉलस्क्यू केवल दो प्रविष्टियों के लिए nce तालिका:

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

इसके अलावा, एक छोटे से प्रयास कोड के सबसे पुन: उपयोग किया जा करने के लिए लिखा जा सकता है (जैसे कस्टम तालिका का पढ़ना, गुण हो रही, जरूरत गुण स्वरूपण और करने के लिए सेट के रूप में कस्टमएक्शनडेटा गुण), और कस्टम एक्शन टेबल में प्रविष्टियां अब एप्लिकेशन विशिष्ट नहीं हैं (एप्लिकेशन विशिष्ट डेटा कस्टम तालिका में लिखा गया है), हम कस्टम एक्शन टेबल को अपनी फाइल में डाल सकते हैं और इसे प्रत्येक वाईएक्स प्रोजेक्ट में शामिल कर सकते हैं ।

कस्टम कार्रवाई डीएलएल फ़ाइल के लिए, क्योंकि कस्टम डेटा से एप्लिकेशन डेटा पढ़ा जाता है, इसलिए हम डीएलएल कार्यान्वयन से एप्लिकेशन विशिष्ट विवरण रख सकते हैं, इसलिए कस्टम एक्शन टेबल लाइब्रेरी बन सकती है और इस प्रकार पुन: उपयोग करना आसान हो जाता है।

इस प्रकार मैं वर्तमान में अपने वाईएक्स कस्टम कार्यों को लिखता हूं, अगर कोई जानता है कि आगे कैसे सुधार किया जाए तो मैं इसकी बहुत सराहना करता हूं। :)

(आप मेरे ब्लॉग पोस्ट, Implementing Wix custom actions part 2: using custom tables में पूरा स्रोत कोड भी पा सकते हैं।)।

3

यदि आपके पास जटिल कस्टम क्रियाएं हैं जिन्हें रोलबैक का समर्थन करने की आवश्यकता है, तो आप एक विक्स एक्सटेंशन लिखने पर विचार कर सकते हैं। एक्सटेंशन आमतौर पर संलेखन समर्थन प्रदान करते हैं (यानी नए एक्सएमएल टैग जो एमएसआई टेबल प्रविष्टियों में मैप किए जाते हैं), साथ ही कस्टम क्रियाओं के स्वचालित शेड्यूलिंग भी प्रदान करते हैं।

यह केवल एक कस्टम कार्रवाई लिखने से अधिक काम है, लेकिन एक बार जब आपका सीए जटिलता के एक निश्चित स्तर तक पहुंच जाता है, तो एक्सटेंशन प्रदान करने वाले आसानी से लेखांकन योग्य हो सकता है।

4

वाईएक्स कस्टम क्रियाएं पालन करने के लिए एक शानदार मॉडल हैं। इस मामले में, आप केवल CustomAction, तत्काल कार्रवाई, स्थगित कार्रवाई, और रोलबैक कार्रवाई के साथ घोषित करते हैं। आप केवल Custom के साथ शेड्यूल करते हैं, तत्काल कार्रवाई, जहां तत्काल कार्रवाई मूल डीएलएल में कोड के रूप में लागू की जाती है।

फिर, तत्काल कार्रवाई की कोड में, आप MsiDoAction फोन रोलबैक और आस्थगित कार्रवाई शेड्यूल करने के लिए: के रूप में वे आस्थगित कर रहे हैं, वे बिंदु पर स्क्रिप्ट में लिखा जाता है आप MsiDoAction बजाय तुरंत मार डाला कहते हैं। कस्टम कार्रवाई डेटा सेट करने के लिए आपको MsiSetProperty पर कॉल करने की आवश्यकता होगी।

वाईएक्स स्रोत कोड डाउनलोड करें और उदाहरण के लिए IISExtension काम करता है। वाईएक्स क्रियाएं आम तौर पर एक कस्टम तालिका का विश्लेषण करती हैं और उस तालिका के आधार पर स्थगित कार्रवाई की संपत्ति के लिए डेटा उत्पन्न करती हैं।

संबंधित मुद्दे