ترقية ميزة فردية في شجرة ميزات WIX دون إلغاء تثبيت/ترقية ميزة (ميزات) أخرى

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

سؤال

أحاول إنشاء مشروع إعداد باستخدام ويكس سيسمح لي ذلك بتثبيت ميزات متعددة لمنتج واحد.كيف يمكنني تحديث إحدى الميزات المثبتة (المستقلة عن الميزات المثبتة الأخرى) دون الحاجة إلى إعادة تثبيت الميزات الأخرى في شجرة الميزات؟

على سبيل المثال ، أريد أن أكون قادرًا على الحصول على مشروع (العودة إلى Hellowolrd) يسمى Hellowolrd ، والذي يطبع (مفاجأة) "Hello World!" على الشاشة.لنفترض أن لدي ثلاثة من تطبيقات helloworld هذه، Hello World 1، وHello World 2، وHello World 3.كل منها يطبع على الشاشة Hello World 1 أو 2 أو 3 بكل احترام.ما أرغب فيه هو إنشاء MSI الذي يقوم افتراضيًا بتثبيت جميع هذه "الميزات" الثلاثة ولكنه يسمح أيضًا بترقية كل ميزة على حدة في وقت لاحق.

هنا هو تخطيطي للحل الخاص بي:

مستكشف الحلول http://img12.imageshack.us/img12/5671/solutionexplorerm.jpg

يبدو ملف WIX Product.wxs الخاص بي كما يلي:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Product Id="ca484210-c719-4b2e-b960-45212d407c11" Name="HelloWorldInstaller" Language="1033" Version="1.0.0.0" Manufacturer="HelloWorldInstaller" UpgradeCode="68eeb8cb-9ef3-443c-870c-9b406129f7ff">
        <Package InstallerVersion="200" Compressed="yes" />

        <Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />

        <!-- Create Directory Structure -->
        <Directory Id="TARGETDIR" Name="SourceDir">
            <Directory Id="ProgramFilesFolder">
                <Directory Id="INSTALLLOCATION" Name="Hello World" />
            </Directory>
            <Directory Id="DesktopFolder" Name="Desktop"/>
        </Directory>

        <DirectoryRef Id="INSTALLLOCATION">
            <Component Id="HelloWorld1" Guid="6D1D9D33-DA17-4db3-8132-C39F32200C3A">
                <RegistryKey Root="HKCU" Key="Software\HelloWorldInstaller\HelloWorld1\Install" Action="createAndRemoveOnUninstall">
                    <RegistryValue Name="DTSC" Value="1" Type="integer" KeyPath="yes" />
                </RegistryKey>

                <File Id="HelloWorld1.exe" Name="$(var.HelloWorld1.TargetFileName)" Source="$(var.HelloWorld1.TargetPath)" DiskId="1" Checksum="yes">
                    <Shortcut Id="HelloWorld1ApplicationDesktopShortcut" Name="Hello World 1" Description="Hello World Application 1" Directory="DesktopFolder" WorkingDirectory="INSTALLLOCATION" />
                </File>

            </Component>
            <Component Id="HelloWorld2" Guid="B2D51F85-358B-41a7-8C45-B4BB341158F8">
                <RegistryKey Root="HKCU" Key="Software\HelloWorldInstaller\HelloWorld2\Install" Action="createAndRemoveOnUninstall">
                    <RegistryValue Name="DTSC" Value="1" Type="integer" KeyPath="yes" />
                </RegistryKey>

                <File Id="HelloWorld2.exe" Name="$(var.HelloWorld2.TargetFileName)" Source="$(var.HelloWorld2.TargetPath)" DiskId="1" Checksum="yes">
                    <Shortcut Id="HelloWorld2ApplicationDesktopShortcut" Name="Hello World 2" Description="Hello World Application 2" Directory="DesktopFolder" WorkingDirectory="INSTALLLOCATION" />
                </File>
            </Component>
            <Component Id="HelloWorld3" Guid="A550223E-792F-4169-90A3-574D4240F3C4">
                <RegistryKey Root="HKCU" Key="Software\HelloWorldInstaller\HelloWorld3\Install" Action="createAndRemoveOnUninstall">
                    <RegistryValue Name="DTSC" Value="1" Type="integer" KeyPath="yes" />
                </RegistryKey>

                <File Id="HelloWorld3.exe" Name="$(var.HelloWorld3.TargetFileName)" Source="$(var.HelloWorld3.TargetPath)" DiskId="1" Checksum="yes">
                    <Shortcut Id="HelloWorld3ApplicationDesktopShortcut" Name="Hello World 3" Description="Hello World Application 3" Directory="DesktopFolder" WorkingDirectory="INSTALLLOCATION" />
                </File>
            </Component>
        </DirectoryRef>

        <Feature Id="HelloWorld1Feature" Title="Hello World 1" Level="1">
            <ComponentRef Id="HelloWorld1"/>
        </Feature>
        <Feature Id="HelloWorld2Feature" Title="Hello World 2" Level="1">
            <ComponentRef Id="HelloWorld2"/>
        </Feature>
        <Feature Id="HelloWorld3Feature" Title="Hello World 3" Level="1">
            <ComponentRef Id="HelloWorld3"/>
        </Feature>

    </Product>
</Wix>

الآن، عندما يتم إنشاء هذا، فإنه يقوم بتثبيت الميزات كما تتوقع.ومع ذلك، عند إجراء تعديل على HelloWorld1.vb وإعادة الترجمة، أود أن يكون قادرًا على إعادة تثبيت (ترقية) هذه الميزة فقط، وليس جميعها.

عندما أقوم بتحديث ملف واحد، وأعيد بناء الحل، ثم أحاول تثبيت msi، يظهر لي هذا الخطأ:

خطأ MSI http://img696.imageshack.us/img696/849/anotherversionisinstall.jpg

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


- تطبيق العالم الحقيقي -

تطبيق العالم الحقيقي لهذا هو حزمة برامج كبيرة تحتاج إلى تطبيقات دعم متعددة تعمل كخدمات/مهام مجدولة على أساس منتظم.أرغب في تثبيت هذه التطبيقات الداعمة في MSI واحد مما يسمح لنا بعدم مواجهة مثل هذا الكابوس المتمثل في طرح كل exe على حدة.أعلم أنه إذا كان لدينا تحديث لأحد ملفات exe، فيمكننا فقط تجميع ملف exe هذا يدويًا وطرحه، ولكنني أرغب في القيام بذلك بطريقة قابلة للتكرار تمامًا.

سيكون موضع تقدير أي مساعدة،

شكرًا لك!

يحرر:

لقد أضفت المصدر للتحميل من كود جوجل.شكرًا لك مرة أخرى!

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

المحلول

لقد اكتشفت هذا واعتقدت أنني سأنشر الإجابة هنا للرجوع إليها مستقبلاً للآخرين.لقد قمت بشرح المشكلة بشكل كامل، وسوف أتعمق أكثر في سيناريو العالم الحقيقي.

لدينا برنامج كبير إلى حد ما يتطلب منا أن يكون لدينا تطبيقات داعمة متعددة تعمل على عدد من الخوادم المختلفة.إن تقدمنا ​​الحالي في الترقيات يجعل من الصعب إلى حد ما ترقية التعليمات البرمجية بطريقة موثوقة.نستخدم حاليًا ملف الاستخراج الذاتي لطرح الكود الخاص بنا على الخوادم المختلفة.تنشأ المشكلة عندما يكون لدينا عدد كبير من التطبيقات الداعمة بحيث يصبح من الصعب التأكد من تثبيت التطبيقات بشكل صحيح باستخدام إعدادات التكوين الصحيحة، وما إلى ذلك.لحل هذه المشكلة، نحن نبحث في القدرة على إنشاء برنامج تثبيت واحد (MSI) بدلاً من ضغط كل من التطبيقات الداعمة، والذي سيسمح لفريق البنية التحتية بتثبيت مجموعة محددة من التطبيقات الداعمة لكل جهاز معين.عندما يكون لدينا تغيير كبير (على سبيل المثال من 1.0 إلى 2.0)، فسنجري تثبيتًا كاملاً للترقية (بمعنى أنه يجب إيقاف جميع الخدمات/العمليات وإلغاء تثبيتها وتثبيتها وبدء تشغيلها.) عندما يكون لدينا تغيير بسيط، نود فقط إيقاف الخدمات/العمليات المتأثرة وإعادة تثبيتها، دون لمس التطبيقات الأخرى.الآن، كفى من التجول، دعنا نصل الحل:

لقد قمت بتعديل WIX Product.wxs لإزالة الاختصارات لأننا لا نحتاج إليها حقًا في السيناريو الخاص بنا.إليك ملف wxs المحدث:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
 <Product Id="13C373D3-5C27-487e-A020-C2C89E4607B1" Name="HelloWorldInstaller" Language="1033" Version="1.0.0.0"
      Manufacturer="HelloWorldInstaller" UpgradeCode="E7CB3C76-4D51-48a8-BFB4-6D11B2E2E65B">

  <Package InstallerVersion="200" Compressed="yes" />

  <Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
  <FeatureRef Id="HelloWorld1Feature" />
  <FeatureRef Id="HelloWorld2Feature" />
  <FeatureRef Id="HelloWorld3Feature" />
 </Product>

 <Fragment>
  <Directory Id="TARGETDIR" Name="SourceDir">
   <Directory Id="ProgramFilesFolder">
    <Directory Id="INSTALLLOCATION" Name="Hello World" />
   </Directory>
   <Directory Id="DesktopFolder" Name="Desktop"/>
  </Directory>
 </Fragment>

 <Fragment>
  <DirectoryRef Id="INSTALLLOCATION">
   <Directory Id="HelloWorld1Directory" Name="Hello World 1">
    <Component Id="HelloWorld1Component" Guid="6D1D9D33-DA17-4db3-8132-C39F32200C3A">
     <File Id="HelloWorld1.exe" Name="HelloWorld1.exe" Source="HelloWorld1.exe" DiskId="1" Checksum="yes" />    
    </Component>
   </Directory>
   <Directory Id="HelloWorld2Directory" Name="Hello World 2">
    <Component Id="HelloWorld2Component" Guid="B2D51F85-358B-41a7-8C45-B4BB341158F8">
     <File Id="HelloWorld2.exe" Name="HelloWorld2.exe" Source="HelloWorld2.exe" DiskId="1" Checksum="yes" />
    </Component>
   </Directory>
   <Directory Id="HelloWorld3Directory" Name="Hello World 3">
    <Component Id="HelloWorld3Component" Guid="A550223E-792F-4169-90A3-574D4240F3C4">
     <File Id="HelloWorld3.exe" Name="HelloWorld3.exe" Source="HelloWorld3.exe" DiskId="1" Checksum="yes" />
    </Component>
   </Directory>
  </DirectoryRef>
 </Fragment>

 <Fragment>
  <Feature Id="HelloWorld1Feature" Title="Hello World 1" Level="1">
   <ComponentRef Id="HelloWorld1Component"/>
  </Feature>
 </Fragment>
 <Fragment>
  <Feature Id="HelloWorld2Feature" Title="Hello World 2" Level="1">
   <ComponentRef Id="HelloWorld2Component"/>
  </Feature>
 </Fragment>
 <Fragment>
  <Feature Id="HelloWorld3Feature" Title="Hello World 3" Level="1">
   <ComponentRef Id="HelloWorld3Component"/>
  </Feature>
 </Fragment>
</Wix>

الآن بالإضافة إلى ذلك، بالنسبة للترقيات البسيطة، سنتطلع إلى إصدار تصحيحات لمكوناتنا.

على سبيل المثال، لنفترض أن لدينا ProductA، والذي يتكون من ثلاثة مكونات - 1،2، و3.يجب تشغيل هذه المكونات الثلاثة إما كخدمات أو مهام مجدولة.طبيعة منتجنا، لا يمكننا إيقاف جميع خدماتنا لتحديث أو إصلاح أحد مكوناتنا.لذا، إذا وجدنا خطأً في المكون 2، بعد تثبيت الإصدار 1.0، لكننا لا نريد أن يتأثر 1 أو 3 بالإصلاح الذي تم تطبيقه على هذا الخطأ، فسنصدر تصحيحًا للمكون 2، وبالتالي سوف يتأثر المكون 2 فقط.

بالنسبة لمثالنا السريع أعلاه، فإننا نستخدم HelloWorld1 وHelloWorld2 وHelloWorld3 كمكوناتنا الثلاثة في تطبيقنا البرمجي.الفكرة هي أننا يجب أن نكون قادرين على تثبيت الثلاثة جميعًا باستخدام MSI واحد، ولكن بعد ذلك نقوم بتحديث كل واحد منهم بشكل مستقل دون التأثير على أي من المكونات الأخرى المثبتة.

لذا، لتوضيح ذلك، قمت بإنشاء تطبيقات وحدة التحكم الثلاثة أعلاه والتي ستعرض "Hello World 1!" و"Hello World 2!" و"Hello World 3!".ثم بعد أن نطلق MSI الأولي، لنفترض أننا عثرنا على "خطأ" يتطلب منا جعل HelloWorld1 يقول "Hello World 1!تم التحديث." بدلاً من ذلك.إليك ما سنفعله لمحاكاة ذلك:

  1. قم بإنشاء Product.wixobj عن طريق تنفيذ هذا الأمر في موجه الأوامر:
    candle.exe Product.wxs
    يرجى تذكر أنه من أجل استدعاء Candle.exe أو أي من أوامر WIX، يجب أن يكون دليل تثبيت Wix موجودًا في متغير PATH الخاص بك.(برنامج تعليمي قصير حول تحديث متغير بيئة PATH) يرجى أيضًا تنفيذ الأوامر الموجودة في نفس الدليل الموجود به ملف Product.wxs الخاص بك.
  2. قم بإنشاء الإصدار الأول من منتجك (لنفترض 1.0):
    light.exe Product.wixobj -out ProductA-1.0.msi
  3. ابحث الآن عن خطأ (قم بتغيير إخراج HelloWorld1 ليقول "Hello World 1!تم التحديث."") ثم تحديث إصدار التجميع وإصدار الملف.هذا مهم لأن هذه هي الطريقة التي يمكن بها لـ WIX معرفة اختلاف ملفات exe.
  4. قم بتشغيل نفس الأمر في الخطوة الأولى (لإجراء جيد):
    candle.exe Product.wxs
  5. قم بتشغيل نفس الأمر تقريبًا مثل الخطوة الثانية:
    light.exe Product.wixobj -out ProductA-1.1.msi
    لاحظ أن هذا هو الإصدار 1.1 بدلاً من 1.0 (هذا هو msi مع الكود المحدث الخاص بنا).ومع ذلك، لا نريد تثبيت هذا فقط، تابع القراءة.
  6. هنا هو الجزء الممتع، لقد حصلنا على الفرق بين جهازي MSI باستخدام الأمر التالي:
    torch.exe -p -xi ProductA-1.0.wixpdb ProductA-1.1.wixpdb -out Diff.WixMst
  7. الآن نقوم بإنشاء ملف التصحيح من هذا (سيتم شرح Patch.wxs أدناه):
    candle.exe Patch.wxs
  8. سنقوم الآن بإنشاء ملف WixMsp باستخدام هذا الأمر:
    light.exe Patch.wixobj -out Patch.WixMsp
  9. والآن الجزء الممتع.قم بإنشاء ملف MSP باستخدام هذا الأمر:
    pyro.exe Patch.WixMsp -out Patch.msp -t RTM Diff.Wixmst

الآن، إذا سار كل شيء وفقًا للخطة، فيجب أن يكون لديك ملفان من نوع msi وملف msp واحد.إذا قمت بتثبيت msi الأول (ProductA-1.0.msi) وقمت بتشغيل HelloWorld1.exe، فمن المفترض أن تشاهد الرسالة "Hello World 1!".للمتعة فقط (وعلى سبيل المثال)، قم بتشغيل كلا التطبيقين الآخرين واتركهما قيد التشغيل (لقد قمت ببناء نقطة توقف لإبقائهما مفتوحين).أغلق HelloWorld1.exe لأننا سنقوم الآن بتطبيق التحديث على ملف exe هذا، ولكن بفعلنا ذلك لن نؤثر على HelloWorld2.exe أو HelloWorld3.exe.إذا قمت الآن بتثبيت ملف msp (Patch.msp)، ثم قمت بتشغيل HelloWorld1.exe، فسترى الرسالة المحدثة، "Hello World 1!محدث."

الآن، بالنسبة ل سحري ملف Patch.wxs:

<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
 <Patch
   AllowRemoval="yes"
   Manufacturer="Dynamo Corp"
   MoreInfoURL="http://www.dynamocorp.com/"
   DisplayName="Sample Patch"
   Description="Small Update Patch"
   Classification="Update"
        >

  <Media Id="5000" Cabinet="RTM.cab">
   <PatchBaseline Id="RTM"/>
  </Media>

  <PatchFamilyRef Id="SamplePatchFamily"/>
 </Patch>

 <Fragment>
  <PatchFamily Id='SamplePatchFamily' Version='1.0.0' Supersede='yes'>
   <ComponentRef Id="HelloWorld1Component"/>
  </PatchFamily>
 </Fragment>
</Wix>

لا يبدو كثيرًا، أليس كذلك؟حسنًا، الأجزاء الأكثر إثارة للاهتمام هي:

  1. <PatchBaseline Id="RTM"/> - هذا، إذا كنت تتذكر، تم استخدامه في إنشاء برنامج التصحيح msi.تمت الإشارة إلى "RTM" في الخطوة الأخيرة أعلاه: -t RTM - هذه يجب أن تتطابق.
  2. <ComponentRef Id="HelloWorld1Component"/> - يؤدي هذا إلى توجيه التصحيح إلى المكون الصحيح المطلوب تحديثه، في حالتنا HelloWorld1Component.

إذا كنت تقوم بالبحث، فقد يبدو الرمز أعلاه مألوفًا لأنه جاء من مدونة بيتر ماركو: ويكس:إنشاء تصحيح باستخدام نظام بناء التصحيح الجديد - الجزء 3

أنا أيضا اعتمدت بشكل كبير على مدونة أليكس شيفتشوك: من MSI إلى WiX، الجزء 8 - الترقية الرئيسية

إذا كنت تتساءل، "رائع، هذه خطوات كثيرة، لماذا يقوم أي شخص بهذا العدد من الخطوات؟"، من فضلك تذكر أنه بمجرد الانتهاء من العمل الشاق (أعلاه)، تحتاج إلى نقل هذا إلى روتين التكامل الخاص بك.هذا صحيح، دمج، دمج، دمج!كيف تفعل هذا؟حسنًا، هذا مزيد من البحث، وربما مشاركة مدونة؟- من المحتمل.لكي تضعك على الطريق الصحيح، إليك مقالة رائعة عن ذلك أتمتة الإصدارات باستخدام MSBuild وWindows Installer XML.

واو، أتمنى أن تقرأ كل هذا (أنتما الاثنان)، وأن تتعلما الكثير.آمل أن يساعد هذا شخصًا آخر غير نفسي.

شكرًا لك!

نصائح أخرى

يبدو أنك اكتشفت سيناريو الترقية ، الآن تحتاج فقط إلى معرفة ذلك مكان وضع RemoveExistingProducts في ترقية MSI الرئيسية بحيث لا يتم إعادة تثبيت الميزات إذا لم تتغير :)

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