กำหนดเป้าหมายทั้ง 32 บิตและ 64 บิตด้วย Visual Studio ในโซลูชัน / โครงการเดียวกัน


111

ฉันมีปัญหาเล็กน้อยเกี่ยวกับวิธีตั้งค่าวิชวลสตูดิโอสำหรับการกำหนดเป้าหมายหลายเป้าหมาย

ความเป็นมา: c # .NET v2.0 พร้อมด้วย p / เรียกใช้ไปยัง 3rd party 32 bit DLL's, SQL compact v3.5 SP1 พร้อมโครงการติดตั้ง ตอนนี้เป้าหมายแพลตฟอร์มถูกตั้งค่าเป็น x86 เพื่อให้สามารถทำงานบน Windows x64 ได้

บริษัท บุคคลที่สามเพิ่งเปิดตัว DLL เวอร์ชัน 64 บิตและฉันต้องการสร้างโปรแกรม 64 บิตโดยเฉพาะ

สิ่งนี้ทำให้เกิดคำถามบางอย่างที่ฉันยังไม่ได้คำตอบ ฉันต้องการมีฐานรหัสเดียวกัน ฉันต้องสร้างโดยอ้างอิงถึงชุด DLL ของ 32 บิตหรือ 64 บิตของ DLL (ทั้งบุคคลที่สามและ SQL Server Compact)

สามารถแก้ไขได้ด้วยการกำหนดค่าใหม่ 2 ชุด (Debug64 และ Release64) หรือไม่

ฉันต้องสร้างโปรเจ็กต์การตั้งค่า 2 โปรเจ็กต์แยกกัน (โปรเจ็กต์สตูดิโอแบบมาตรฐานไม่มี Wix หรือยูทิลิตี้อื่น ๆ ) หรือจะแก้ไขได้ภายใน. msi เดียวกันหรือไม่

ยินดีรับความคิดเห็นและ / หรือข้อเสนอแนะ


@Magnus Johansson: คุณสามารถใช้การกำหนดค่าสองแบบเพื่อบรรลุเป้าหมายครึ่งหนึ่ง MSI นั้นยากกว่าเล็กน้อย
user7116

คำตอบ:


83

ได้คุณสามารถกำหนดเป้าหมายทั้ง x86 และ x64 ด้วยฐานรหัสเดียวกันในโปรเจ็กต์เดียวกัน โดยทั่วไปสิ่งต่างๆจะใช้งานได้หากคุณสร้างการกำหนดค่าโซลูชันที่เหมาะสมใน VS.NET (แม้ว่า P / Invoke ไปยัง DLL ที่ไม่มีการจัดการทั้งหมดมักจะต้องใช้รหัสเงื่อนไขบางอย่าง): รายการที่ฉันพบว่าต้องให้ความสนใจเป็นพิเศษ ได้แก่ :

  • การอ้างอิงไปยังแอสเซมบลีที่มีการจัดการภายนอกที่มีชื่อเดียวกัน แต่มีบิตเนสเฉพาะของตัวเอง (ซึ่งใช้กับแอสเซมบลีการทำงานร่วมกันของ COM)
  • แพ็คเกจ MSI (ตามที่ได้ระบุไว้แล้วว่าจะต้องกำหนดเป้าหมายเป็น x86 หรือ x64)
  • การดำเนินการที่ใช้. NET Installer Class แบบกำหนดเองในแพ็คเกจ MSI ของคุณ

ปัญหาการอ้างอิงแอสเซมบลีไม่สามารถแก้ไขได้ทั้งหมดภายใน VS.NET เนื่องจากจะอนุญาตให้คุณเพิ่มการอ้างอิงที่มีชื่อที่กำหนดให้กับโปรเจ็กต์ได้เพียงครั้งเดียว ในการแก้ไขปัญหานี้แก้ไขไฟล์โครงการของคุณด้วยตนเอง (ใน VS คลิกขวาที่ไฟล์โครงการของคุณใน Solution Explorer เลือก Unload Project จากนั้นคลิกขวาอีกครั้งแล้วเลือก Edit) หลังจากเพิ่มการอ้างอิงถึงแอสเซมบลีเวอร์ชัน x86 ไฟล์โปรเจ็กต์ของคุณจะประกอบด้วยสิ่งต่างๆเช่น:

<Reference Include="Filename, ..., processorArchitecture=x86">
  <HintPath>C:\path\to\x86\DLL</HintPath>
</Reference>

ห่อแท็กอ้างอิงนั้นไว้ภายในแท็ก ItemGroup ที่ระบุการกำหนดค่าโซลูชันที่ใช้กับเช่น:

<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
   <Reference ...>....</Reference>
</ItemGroup>

จากนั้นคัดลอกและวางแท็ก ItemGroup ทั้งหมดและแก้ไขให้มีรายละเอียดของ DLL 64 บิตของคุณเช่น:

<ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
  <Reference Include="Filename, ..., processorArchitecture=AMD64">
     <HintPath>C:\path\to\x64\DLL</HintPath>
   </Reference>
</ItemGroup>

หลังจากโหลดโปรเจ็กต์ของคุณใหม่ใน VS.NET กล่องโต้ตอบการอ้างอิงแอสเซมบลีจะสับสนเล็กน้อยกับการเปลี่ยนแปลงเหล่านี้และคุณอาจพบคำเตือนบางอย่างเกี่ยวกับแอสเซมบลีกับตัวประมวลผลเป้าหมายที่ไม่ถูกต้อง แต่งานสร้างทั้งหมดของคุณจะทำงานได้ดี

การแก้ปัญหา MSI เป็นเรื่องต่อไปและน่าเสียดายที่สิ่งนี้จะต้องใช้เครื่องมือที่ไม่ใช่ VS.NET: ฉันชอบตัวติดตั้งขั้นสูงของ Caphyon เพื่อจุดประสงค์นั้นเนื่องจากมันดึงเคล็ดลับพื้นฐานที่เกี่ยวข้องออกไป (สร้าง MSI ทั่วไปรวมทั้ง 32 บิต และ MSI เฉพาะ 64 บิตและใช้ตัวเรียกใช้การตั้งค่า. EXE เพื่อแยกเวอร์ชันที่ถูกต้องและทำการแก้ไขที่จำเป็นในรันไทม์) ได้เป็นอย่างดี

คุณอาจได้ผลลัพธ์เดียวกันโดยใช้เครื่องมืออื่น ๆ หรือชุดเครื่องมือWindows Installer XML (WiX)แต่ Advanced Installer ทำให้สิ่งต่าง ๆ ง่ายมาก (และราคาไม่แพงเลย) ซึ่งฉันไม่เคยมองหาทางเลือกอื่นเลย

สิ่งหนึ่งที่คุณอาจยังต้องใช้ WiX แม้ว่าจะใช้โปรแกรมติดตั้งขั้นสูง แต่ก็มีไว้สำหรับการดำเนินการแบบกำหนดเองของ. NET Installer Class แม้ว่าจะเป็นเรื่องเล็กน้อยในการระบุการกระทำบางอย่างที่ควรทำงานบนบางแพลตฟอร์มเท่านั้น (โดยใช้เงื่อนไขการดำเนินการ VersionNT64 และ NOT VersionNT64 ตามลำดับ) การดำเนินการแบบกำหนดเองของ AI ในตัวจะดำเนินการโดยใช้ Framework 32 บิตแม้ในเครื่อง 64 บิต .

สิ่งนี้อาจได้รับการแก้ไขในรุ่นในอนาคต แต่สำหรับตอนนี้ (หรือเมื่อใช้เครื่องมืออื่นในการสร้าง MSI ของคุณที่มีปัญหาเดียวกัน) คุณสามารถใช้การสนับสนุนการดำเนินการที่กำหนดเองที่มีการจัดการของ WiX 3.0 เพื่อสร้าง DLL การดำเนินการที่มีบิตที่เหมาะสมที่ จะดำเนินการโดยใช้ Framework ที่เกี่ยวข้อง


แก้ไข: ในเวอร์ชัน 8.1.2 โปรแกรมติดตั้งขั้นสูงรองรับการกระทำแบบกำหนดเอง 64 บิตอย่างถูกต้อง เนื่องจากคำตอบเดิมของฉันราคาจึงเพิ่มขึ้นเล็กน้อย แต่น่าเสียดายที่แม้ว่าจะยังคงคุ้มค่ามากเมื่อเทียบกับ InstallShield และ ilk ...


แก้ไข: หาก DLL ของคุณลงทะเบียนใน GAC คุณยังสามารถใช้แท็กอ้างอิงมาตรฐานด้วยวิธีนี้ (SQLite เป็นตัวอย่าง):

<ItemGroup Condition="'$(Platform)' == 'x86'">
    <Reference Include="System.Data.SQLite, Version=1.0.80.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=x86" />
</ItemGroup>
<ItemGroup Condition="'$(Platform)' == 'x64'">
    <Reference Include="System.Data.SQLite, Version=1.0.80.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=AMD64" />
</ItemGroup>

เงื่อนไขนี้ยังลดลงเป็นประเภทบิวด์รีลีสหรือดีบักทั้งหมดและระบุสถาปัตยกรรมโปรเซสเซอร์เท่านั้น


ใน Visual Studio 2008 ฉันพบว่าไม่สามารถซ้อน <ItemGroup> ได้ โซลูชันนี้ทำงานได้ดีเมื่อฉันสร้าง <ItemGroup> ใหม่ด้านล่างกลุ่มส่วนที่เหลือของ <Reference> s ฉันต้องเปลี่ยน x86 เป็น AnyCPU ด้วยซึ่งอาจเกี่ยวข้องกับประวัติของโครงการเฉพาะของฉัน
Oliver Bock

โปรแกรมติดตั้งขั้นสูงนั้นดูดีทีเดียว
แพท

นี่อาจเป็นคำถามโง่ ๆ แต่คุณจะไปที่ไฟล์เพื่อแก้ไขด้วยตนเองได้อย่างไร?
ชม

1
หากต้องการแก้ไขไฟล์ภายใน VS ให้คลิกขวาที่โปรเจ็กต์ใน Solution Explorer และค้นหา "Unload Project" เมื่อยกเลิกการโหลดโปรเจ็กต์แล้วให้คลิกขวาที่โปรเจ็กต์อีกครั้งและคลิกที่ "แก้ไข <ชื่อไฟล์โปรเจ็กต์>" หลังจากคุณแก้ไขไฟล์โครงการแล้วให้บันทึกและคลิกขวาที่ไฟล์โครงการอีกครั้งแล้วโหลด หากไม่มีการพิมพ์ผิดหรือข้อผิดพลาดจะโหลดอีกครั้ง ถ้าไม่ VS จะบอกคุณได้อย่างชัดเจนว่าไฟล์มีปัญหาอะไร หวังว่าจะช่วยได้!
John Baughman

ตอบโจทย์มาก! ขอบคุณ!
John Baughman

27

สมมติว่าคุณมีการสร้าง DLL สำหรับทั้งสองแพลตฟอร์มและอยู่ในตำแหน่งต่อไปนี้:

C:\whatever\x86\whatever.dll
C:\whatever\x64\whatever.dll

คุณต้องแก้ไขไฟล์. csproj ของคุณจากสิ่งนี้:

<HintPath>C:\whatever\x86\whatever.dll</HintPath>

สำหรับสิ่งนี้:

<HintPath>C:\whatever\$(Platform)\whatever.dll</HintPath>

จากนั้นคุณจะสามารถสร้างโครงการของคุณที่กำหนดเป้าหมายทั้งสองแพลตฟอร์มได้และ MSBuild จะค้นหาในไดเรกทอรีที่ถูกต้องสำหรับแพลตฟอร์มที่เลือก


สิ่งนี้จะยอดเยี่ยมถ้ามันใช้งานได้ แต่ไม่เป็นเช่นนั้น อย่างน้อยก็ไม่ใช่สำหรับฉัน
John Sheehan

10
นั่นไม่ควรจะเป็น: <HintPath> C: \ anything \ $ (Platform) \ anything.dll </HintPath>
Andreas

ทำงานได้ดีบน Visual Studio 2008 สำหรับฉัน แต่ไม่ได้คัดลอก DLL ไปยังไดเร็กทอรีเป้าหมายของบิลด์โดยอัตโนมัติเหมือนที่ <Reference> ปกติทำ โซลูชันของ mdb ทำงานได้ดีขึ้นสำหรับฉัน
Oliver Bock

1

ไม่แน่ใจในคำตอบทั้งหมดสำหรับคำถามของคุณ - แต่คิดว่าฉันจะชี้ให้เห็นความคิดเห็นในส่วนข้อมูลเพิ่มเติมของหน้าดาวน์โหลด SQL Compact 3.5 SP1 เมื่อเห็นว่าคุณกำลังดู x64 - หวังว่าจะช่วยได้

เนื่องจากการเปลี่ยนแปลงใน SQL Server Compact SP1 และการสนับสนุนเวอร์ชัน 64 บิตเพิ่มเติมการติดตั้งจากส่วนกลางและสภาพแวดล้อมโหมดผสมของ SQL Server Compact 3.5 รุ่น 32 บิตและ SQL Server Compact 3.5 SP1 รุ่น 64 บิตสามารถสร้างสิ่งที่ดูเหมือนจะไม่ต่อเนื่อง ปัญหา. เพื่อลดโอกาสที่จะเกิดข้อขัดแย้งให้น้อยที่สุดและเพื่อเปิดใช้งานการปรับใช้แอ็พพลิเคชันไคลเอนต์ที่มีการจัดการแบบเป็นกลางการติดตั้ง SQL Server Compact 3.5 SP1 รุ่น 64 บิตจากส่วนกลางโดยใช้ไฟล์ Windows Installer (MSI) จำเป็นต้องติดตั้ง SQL Server เวอร์ชัน 32 บิต ไฟล์ MSI 3.5 SP1 ขนาดกะทัดรัด สำหรับแอ็พพลิเคชันที่ต้องการเฉพาะ 64 บิตดั้งเดิมเท่านั้นการปรับใช้แบบส่วนตัวของ SQL Server Compact 3.5 SP1 รุ่น 64 บิตสามารถใช้งานได้

ฉันอ่านสิ่งนี้ว่า "รวมไฟล์ SQLCE 32 บิตเช่นเดียวกับไฟล์ 64bit ว่า" ถ้ากระจายสำหรับ 64bit ลูกค้า

ทำให้ชีวิตน่าสนใจฉันเดาว่า .. ต้องบอกว่าฉันชอบแนว "สิ่งที่ดูเหมือนจะเป็นปัญหาไม่ต่อเนื่อง" ... ฟังดูเหมือน "คุณกำลังจินตนาการถึงสิ่งต่างๆ แต่ในกรณีที่ทำสิ่งนี้ ... "


1

หนึ่ง. Net build ที่มีการอ้างอิง x86 / x64

ในขณะที่คำตอบอื่น ๆ ทั้งหมดให้วิธีแก้ปัญหาในการสร้างงานสร้างที่แตกต่างกันตามแพลตฟอร์ม แต่ฉันให้ตัวเลือกแก่คุณในการกำหนดค่า "AnyCPU" และสร้างบิลด์ที่ใช้งานได้กับ x86 และ x64 dll ของคุณ

คุณต้องเขียนรหัสท่อประปาสำหรับสิ่งนี้

ความละเอียดของ x86 / x64-dlls ที่ถูกต้องที่รันไทม์

ขั้นตอน:

  1. ใช้ AnyCPU ใน csproj
  2. ตัดสินใจว่าคุณอ้างอิงเฉพาะ x86 หรือ x64 dlls ใน csprojs ของคุณ ปรับการตั้งค่า UnitTests ให้เข้ากับการตั้งค่าสถาปัตยกรรมที่คุณเลือก สิ่งสำคัญสำหรับการดีบัก / เรียกใช้การทดสอบภายใน VisualStudio
  3. เมื่อวันที่อ้างอิง-คุณสมบัติตั้งคัดลอกท้องถิ่นและเฉพาะรุ่นที่จะเท็จ
  4. กำจัดคำเตือนสถาปัตยกรรมโดยเพิ่มบรรทัดนี้ในPropertyGroupแรกในไฟล์ csproj ทั้งหมดของคุณที่คุณอ้างอิง x86 / x64: <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. เพิ่มสคริปต์ postbuild นี้ในโปรเจ็กต์เริ่มต้นของคุณใช้และแก้ไขเส้นทางของสคริปต์นี้ sp ที่คัดลอก x86 / x64 dlls ทั้งหมดของคุณในโฟลเดอร์ย่อยที่สอดคล้องกันของ build bin \ x86 \ bin \ x64 \

    xcopy /E /H /R /Y /I /D $(SolutionDir)\YourPathToX86Dlls $(TargetDir)\x86 xcopy /E /H /R /Y /I /D $(SolutionDir)\YourPathToX64Dlls $(TargetDir)\x64

    -> เมื่อคุณจะเริ่มแอปพลิเคชันตอนนี้คุณจะได้รับข้อยกเว้นว่าไม่พบชุดประกอบ

  6. ลงทะเบียนเหตุการณ์ AssemblyResolve ที่จุดเริ่มต้นของจุดเข้าแอปพลิเคชันของคุณ

    AppDomain.CurrentDomain.AssemblyResolve += TryResolveArchitectureDependency;

    ด้วยวิธีนี้:

    /// <summary>
    /// Event Handler for AppDomain.CurrentDomain.AssemblyResolve
    /// </summary>
    /// <param name="sender">The app domain</param>
    /// <param name="resolveEventArgs">The resolve event args</param>
    /// <returns>The architecture dependent assembly</returns>
    public static Assembly TryResolveArchitectureDependency(object sender, ResolveEventArgs resolveEventArgs)
    {
        var dllName = resolveEventArgs.Name.Substring(0, resolveEventArgs.Name.IndexOf(","));
    
        var anyCpuAssemblyPath = $".\\{dllName}.dll";
    
        var architectureName = System.Environment.Is64BitProcess ? "x64" : "x86";
    
        var assemblyPath = $".\\{architectureName}\\{dllName}.dll";
    
        if (File.Exists(assemblyPath))
        {
            return Assembly.LoadFrom(assemblyPath);
        }
    
        return null;
    }
  7. หากคุณมีการทดสอบหน่วยให้ทำ TestClass ด้วย Method ที่มี AssemblyInitializeAttribute และลงทะเบียน TryResolveArchitectureDependency-Handler ข้างต้นที่นั่น (สิ่งนี้จะไม่ถูกดำเนินการในบางครั้งหากคุณเรียกใช้การทดสอบเดี่ยวภายในวิชวลสตูดิโอการอ้างอิงจะได้รับการแก้ไขไม่ได้มาจากถังทดสอบ UnitTest ดังนั้นการตัดสินใจในขั้นตอนที่ 2 จึงมีความสำคัญ)

สิทธิประโยชน์:

  • หนึ่งการติดตั้ง / สร้างสำหรับทั้งสองแพลตฟอร์ม

ข้อเสีย: - ไม่มีข้อผิดพลาดในเวลาคอมไพล์เมื่อ x86 / x64 dll ไม่ตรงกัน - คุณควรทำการทดสอบในทั้งสองโหมด!

เลือกที่จะสร้างไฟล์ปฏิบัติการที่สองซึ่งเป็นเอกสิทธิ์สำหรับสถาปัตยกรรม x64 ด้วย Corflags.exe ในสคริปต์ postbuild

ตัวแปรอื่น ๆ ที่ควรทดลองใช้: - คุณไม่จำเป็นต้องใช้ตัวจัดการเหตุการณ์ AssemblyResolve หากคุณมั่นใจว่า dlls ที่ถูกต้องจะถูกคัดลอกไปยังโฟลเดอร์ไบนารีของคุณเมื่อเริ่มต้น (สถาปัตยกรรมการประเมินกระบวนการ -> ย้าย dll ที่เกี่ยวข้องจาก x64 / x86 ไปยังโฟลเดอร์ bin และย้อนกลับ ) - ในโปรแกรมติดตั้งประเมินสถาปัตยกรรมและลบไบนารีสำหรับสถาปัตยกรรมที่ไม่ถูกต้องและย้ายสิ่งที่ถูกต้องไปยังโฟลเดอร์ถังขยะ


0

เกี่ยวกับคำถามสุดท้ายของคุณ เป็นไปได้มากว่าคุณไม่สามารถแก้ปัญหานี้ได้ภายใน MSI เครื่องเดียว หากคุณใช้โฟลเดอร์รีจิสตรี / ระบบหรืออะไรก็ตามที่เกี่ยวข้อง MSI เองต้องตระหนักถึงสิ่งนี้และคุณต้องเตรียม MSI 64 บิตเพื่อติดตั้งบนเครื่อง 32 บิตอย่างถูกต้อง

มีความเป็นไปได้ที่คุณสามารถทำให้ผลิตภัณฑ์ของคุณติดตั้งเป็นแอปพลิเคชัน 32 it และยังคงสามารถทำให้มันทำงานเป็น 64 บิตได้ แต่ฉันคิดว่ามันอาจจะค่อนข้างยากที่จะบรรลุ

ที่ถูกกล่าวว่าฉันคิดว่าคุณควรจะสามารถใช้ฐานรหัสเดียวสำหรับทุกสิ่งได้ ในสถานที่ทำงานปัจจุบันของฉันเราได้จัดการให้แล้ว (แต่ต้องใช้การเล่นกลเพื่อให้ทุกอย่างเข้ากันได้)

หวังว่านี่จะช่วยได้ นี่คือลิงก์ไปยังข้อมูลบางอย่างที่เกี่ยวข้องกับปัญหา 32/64 บิต: http://blog.typemock.com/2008/07/registry-on-windows-64-bit-double-your.html


0

หากคุณใช้ Custom Actions ที่เขียนใน. NET เป็นส่วนหนึ่งของโปรแกรมติดตั้ง MSI ของคุณแสดงว่าคุณมีปัญหาอื่น

'shim' ที่เรียกใช้การกระทำที่กำหนดเองเหล่านี้จะเป็น 32 บิตเสมอจากนั้นการกระทำที่กำหนดเองของคุณจะทำงานเป็น 32 บิตเช่นกันแม้ว่าคุณจะระบุเป้าหมายใดก็ตาม

ข้อมูลเพิ่มเติมและการเคลื่อนไหวของนินจาเพื่อเดินทางไปรอบ ๆ (โดยทั่วไปเปลี่ยน MSI ให้ใช้รุ่น 64 บิตของ shim นี้)

การสร้าง MSI ใน Visual Studio 2005/2008 เพื่อทำงานบน SharePoint 64

การดำเนินการแบบกำหนดเองที่มีการจัดการ 64 บิตด้วย Visual Studio


0

คุณสามารถสร้างสองโซลูชันที่แตกต่างกันและรวมเข้าด้วยกันในภายหลัง! ฉันทำสิ่งนี้สำหรับ VS 2010 และได้ผล ฉันมีโซลูชันที่แตกต่างกัน 2 แบบที่สร้างโดย CMake และฉันก็รวมเข้าด้วยกัน


0

คุณสามารถใช้เงื่อนไขกับItemGroupสำหรับการอ้างอิง dll ในไฟล์โครงการ
สิ่งนี้จะทำให้ Visual Studio ตรวจสอบเงื่อนไขและการอ้างอิงอีกครั้งเมื่อใดก็ตามที่คุณเปลี่ยนการกำหนดค่าที่ใช้งานอยู่
เพียงเพิ่มเงื่อนไขสำหรับการกำหนดค่าแต่ละรายการ

ตัวอย่าง:

 <ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <Reference Include="DLLName">
      <HintPath>..\DLLName.dll</HintPath>
    </Reference>
    <ProjectReference Include="..\MyOtherProject.vcxproj">
      <Project>{AAAAAA-000000-BBBB-CCCC-TTTTTTTTTT}</Project>
      <Name>MyOtherProject</Name>
    </ProjectReference>
  </ItemGroup>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.