it-swarm.com.de

Targeting von 32 Bit und 64 Bit mit Visual Studio in derselben Lösung/in einem Projekt

Ich habe ein kleines Dilemma, wie ich meine Visual Studio Builds für Multi-Targeting einrichten kann.

Hintergrund: c # .NET v2.0 mit p/Aufruf in 32-Bit-DLLs von Drittanbietern, SQL compact v3.5 SP1, mit einem Setup-Projekt. Derzeit ist das Plattformziel auf x86 festgelegt, sodass es unter Windows x64 ausgeführt werden kann.

Die Fremdfirma hat gerade 64-Bit-Versionen ihrer DLLs veröffentlicht, und ich möchte ein dediziertes 64-Bit-Programm erstellen.

Dies wirft einige Fragen auf, auf die ich noch keine Antworten habe ... Ich möchte die gleiche Codebasis haben. Ich muss mit Verweisen auf den 32-Bit-Satz von DLLs oder 64-Bit-DLLs aufbauen. (Sowohl von Drittanbietern als auch von SQL Server Compact)

Kann dies mit zwei neuen Konfigurationssätzen (Debug64 und Release64) gelöst werden?

Muss ich zwei separate Setup-Projekte erstellen (standardmäßige Visual Studio-Projekte, kein Wix oder ein anderes Dienstprogramm), oder kann dies innerhalb derselben .msi-Datei gelöst werden?

Alle Ideen und/oder Empfehlungen sind zu begrüßen.

104

Ja, Sie können sowohl x86 als auch x64 mit derselben Codebasis in demselben Projekt anvisieren. Im Allgemeinen funktionieren die Dinge einfach, wenn Sie die richtigen Lösungskonfigurationen in VS.NET erstellen (obwohl P/Invoke für vollständig nicht verwaltete DLLs höchstwahrscheinlich bedingten Code erfordern wird): Die Elemente, für die ich besondere Aufmerksamkeit benötigte, sind:

  • Verweise auf externe verwaltete Assemblys mit demselben Namen, jedoch mit ihrer eigenen spezifischen Bittigkeit (dies gilt auch für COM-Interop-Assemblys)
  • Das MSI-Paket (das, wie bereits erwähnt wurde, muss entweder auf x86 oder x64 ausgerichtet sein)
  • Alle benutzerdefinierten .NET-Installationsprogramme Klassenbasierte Aktionen in Ihrem MSI-Paket

Das Assembly-Referenzproblem kann nicht vollständig in VS.NET gelöst werden, da Sie einem Projekt nur einmal eine Referenz mit einem bestimmten Namen hinzufügen können. Um dies zu umgehen, bearbeiten Sie Ihre Projektdatei manuell (klicken Sie in VS im Projektmappen-Explorer mit der rechten Maustaste auf Ihre Projektdatei, wählen Sie Projekt entfernen, klicken Sie erneut mit der rechten Maustaste und wählen Sie Bearbeiten). Nachdem Sie beispielsweise einen Verweis auf die x86-Version einer Assembly hinzugefügt haben, enthält Ihre Projektdatei Folgendes:

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

Umschließen Sie das Reference-Tag in ein ItemGroup-Tag, das die Lösungskonfiguration angibt, für die es gilt, z.

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

Kopieren Sie dann das gesamte ItemGroup-Tag, fügen Sie es ein und bearbeiten Sie es, um die Details Ihrer 64-Bit-DLL zu enthalten, z.

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

Nach dem erneuten Laden Ihres Projekts in VS.NET wird der Assembly Reference-Dialog durch diese Änderungen etwas verwirrt. Möglicherweise werden einige Warnungen über Assemblys mit dem falschen Zielprozessor angezeigt. Alle Builds funktionieren jedoch einwandfrei.

Die Lösung des MSI-Problems steht als nächstes an, und leider ist dies der Fall werden Benötigen Sie ein Nicht-VS.NET-Tool: Ich bevorzuge Caphyon's Advanced Installer , da dies den grundlegenden Trick mit sich bringt (erstellen Sie eine gemeinsame MSI sowie 32-Bit- und 64-Bit-spezifische MSIs und Verwenden Sie ein .EXE-Setup-Startprogramm, um die richtige Version zu extrahieren und die erforderlichen Korrekturen zur Laufzeit durchzuführen. Sehr, sehr gut. 

Sie können wahrscheinlich dieselben Ergebnisse mit anderen Tools oder dem Windows Installer XML (WiX) -Toolset erzielen, aber Advanced Installer macht die Sache so einfach (und das ist durchaus erschwinglich), so dass ich noch nie wirklich nach Alternativen gesucht habe.

Eine Sache du kann Sie benötigen jedoch weiterhin WiX, selbst wenn Sie Advanced Installer verwenden, gelten die benutzerdefinierten Aktionen der .NET Installer-Klasse. Es ist zwar trivial, bestimmte Aktionen anzugeben, die nur auf bestimmten Plattformen (unter den Ausführungsbedingungen VersionNT64 und NOT VersionNT64) ausgeführt werden sollen, die integrierten benutzerdefinierten AI-Aktionen werden jedoch auch auf 64-Bit-Maschinen mit dem 32-Bit-Framework ausgeführt .

Dies kann in einer zukünftigen Version behoben werden. Für den Moment (oder wenn Sie ein anderes Tool zum Erstellen Ihrer MSIs verwenden, bei dem dasselbe Problem auftritt) können Sie die Unterstützung für verwaltete benutzerdefinierte Aktionen von WiX 3.0 verwenden, um Aktions-DLLs mit der richtigen Bitness zu erstellen wird mit dem entsprechenden Framework ausgeführt.


Bearbeiten: Ab Version 8.1.2 unterstützt Advanced Installer ordnungsgemäß benutzerdefinierte 64-Bit-Aktionen. Seit meiner ursprünglichen Antwort ist der Preis leider ein wenig gestiegen, auch wenn er im Vergleich zu InstallShield und seinen Produkten immer noch extrem günstig ist ...


Bearbeiten: Wenn Ihre DLLs im GAC registriert sind, können Sie auf diese Weise auch die Standardreferenztags verwenden (SQLite als Beispiel):

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

Die Bedingung wird auch auf alle Build-Typen, Release oder Debugging reduziert und gibt lediglich die Prozessorarchitektur an.

81
mdb

Angenommen, Sie haben die DLLs für beide Plattformen erstellt und befinden sich an folgendem Speicherort:

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

Sie müssen lediglich Ihre .csproj-Datei von hier aus bearbeiten:

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

Zu diesem:

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

Sie sollten dann in der Lage sein, Ihr Projekt für beide Plattformen zu erstellen, und MSBuild sucht im richtigen Verzeichnis für die ausgewählte Plattform.

27
Tim Booker

Ich bin mir nicht sicher, welche Antwort auf Ihre Frage insgesamt gegeben wurde - aber ich dachte, ich würde im Abschnitt "Zusätzliche Informationen" der SQL Compact 3.5 SP1-Downloadseite auf einen Kommentar hinweisen, wenn Sie x64 betrachten. Ich hoffe, es hilft.

Aufgrund von Änderungen in SQL Server Compact SP1 und zusätzliche 64-Bit-Version Support, zentral installiert und gemischt Modusumgebungen der 32-Bit-Version von SQL Server Compact 3.5 und 64-Bit Version von SQL Server Compact 3.5 SP1 kann erstellen, was scheinbar .__ ist. zeitweilige Probleme. So minimieren Sie die Konfliktpotential und .__ zu ermöglichen. plattformneutrale Bereitstellung von verwaltetem Clientanwendungen, zentral Installieren der 64-Bit-Version von SQL Server Compact 3.5 SP1 mit Windows Installer (MSI) -Datei ebenfalls erfordert die Installation der 32-Bit-Version von SQL Server Compact 3.5 SP1 MSI Datei. Für Anwendungen, die nur Native 64-Bit, privat Bereitstellung der 64-Bit-Version von SQL Server Compact 3.5 SP1 kann .__ sein. verwendet.

Ich las dies als "die 32-Bit-SQLCE-Dateien sowie die 64-Bit-Dateien einschließen", wenn für 64-Bit-Clients verteilt wird. 

Macht das Leben interessant Ich denke, ich muss sagen, ich liebe die Zeile "Was scheint als zeitweilige Probleme zu sein".

1
gleng

Sie können eine Bedingung für eine ItemGroup für die DLL-Referenzen in der Projektdatei verwenden.
Dies bewirkt, dass Visual Studio die Bedingungen und Verweise jedes Mal überprüft, wenn Sie die aktive Konfiguration ändern.
Fügen Sie einfach eine Bedingung für jede Konfiguration hinzu.

Beispiel:

 <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>
0
Yochai Timmer

Ein .Net-Build mit x86/x64-Abhängigkeiten

Während alle anderen Antworten eine Lösung für unterschiedliche Builds je nach Plattform bieten, gebe ich Ihnen die Option, nur die Konfiguration "AnyCPU" zu verwenden und ein Build zu erstellen, das mit Ihren x86- und x64-DLLs funktioniert.

Sie müssen dazu einen Klempnercode schreiben. Ich konnte dies nicht mit app.config zum Laufen bringen. Wenn jemand anderes über app.config einen Lösungsweg kennt, würde ich das gerne wissen.

Auflösung von korrekten x86/x64-dlls zur Laufzeit

Schritte:

  1. Verwenden Sie AnyCPU in csproj
  2. Entscheiden Sie, ob Sie nur die x86- oder die x64-DLLs in Ihren Csprojs referenzieren. Passen Sie die UnitTests-Einstellungen an die von Ihnen gewählten Architektureinstellungen an. Dies ist wichtig für das Debuggen und Ausführen der Tests in VisualStudio.
  3. Auf Referenz-Eigenschaften gesetzt Lokal kopieren & Spezifische Version nach false
  4. Beseitigen Sie die Architekturwarnungen, indem Sie diese Zeile in allen Ihren csproj-Dateien, in denen Sie auf x86/x64 verweisen, der ersten PropertyGroup hinzufügen: <ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
  5. Fügen Sie dieses Postbuild-Skript zu Ihrem Startprojekt hinzu. Verwenden Sie die Pfade dieses Skripts, und ändern Sie sie, um alle Ihre x86/x64-DLLs in die entsprechenden Unterordner des Build-Abschnitts\x86\bin\x64\zu kopieren.

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

    -> Wenn Sie die Anwendung jetzt starten, erhalten Sie eine Ausnahme , Dass die Assembly nicht gefunden werden konnte.

  6. Registrieren Sie das AssemblyResolve-Ereignis direkt am Anfang Ihres Anwendungseingangspunkts

    AppDomain.CurrentDomain.AssemblyResolve += TryResolveArchitectureDependency;
    

    mit dieser Methode:

    /// <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. Wenn Sie Unit-Tests haben, erstellen Sie eine TestClass mit einer Methode, die über ein AssemblyInitializeAttribute verfügt, und registrieren Sie dort auch den obigen TryResolveArchitectureDependency-Handler. (Dies wird manchmal nicht ausgeführt, wenn Sie einzelne Tests in Visual Studio ausführen. Die Referenzen werden nicht aus der UnitTest-Ablage gelöst. Daher ist die Entscheidung in Schritt 2 wichtig.)

Leistungen:

  • Eine Installation/Erstellung für beide Plattformen

Nachteile: - Keine Fehler zur Kompilierzeit, wenn x86/x64-DLLs nicht übereinstimmen . - Sie sollten noch in beiden Modi testen!

Erstellen Sie optional eine zweite ausführbare Datei, die für die x64-Architektur exklusiv ist, mit Corflags.exe im Postbuild-Skript

Andere Varianten zum Ausprobieren: - Sie benötigen den AssemblyResolve-Ereignishandler nicht, wenn Sie andernfalls sicherstellen, dass die DLLs beim Start in Ihren Binärordner kopiert werden (Prozessarchitektur bewerten -> entsprechende DLLs aus x64/x86 in den bin-Ordner und zurück verschieben.) - Überprüfen Sie im Installationsprogramm die Architektur und löschen Sie die Binärdateien für eine falsche Architektur, und verschieben Sie die richtigen in den Ordner bin.

0
Felix Keil

Wenn Sie in .NET geschriebene benutzerdefinierte Aktionen als Teil Ihres MSI-Installationsprogramms verwenden, liegt ein anderes Problem vor.

Das "Shim", das diese benutzerdefinierten Aktionen ausführt, ist immer 32-Bit, dann wird Ihre benutzerdefinierte Aktion trotz des von Ihnen angegebenen Ziels auch 32-Bit ausgeführt.

Mehr Infos & ein paar Ninja-Züge, um herumzukommen (ändern Sie grundsätzlich das MSI, um die 64-Bit-Version dieses Shims zu verwenden)

Erstellen eines MSI in Visual Studio 2005/2008 zum Arbeiten mit einem SharePoint 64

Verwaltete benutzerdefinierte 64-Bit-Aktionen mit Visual Studio

0
Ryan

Zu deiner letzten Frage. Wahrscheinlich können Sie dieses Problem nicht in einem einzigen MSI lösen. Wenn Sie Registrierungs-/Systemordner oder verwandte Elemente verwenden, muss das MSI selbst darüber informiert sein und Sie müssen ein 64-Bit-MSI für die ordnungsgemäße Installation auf einem 32-Bit-Computer vorbereiten.

Es besteht die Möglichkeit, dass Sie Ihr Produkt als 32-Bit-Anwendung installieren und trotzdem als 64-Bit-Anwendung ausführen lassen, aber ich denke, das kann etwas schwierig sein.

ich denke, Sie sollten eine einzige Codebasis für alles behalten können. An meinem jetzigen Arbeitsplatz ist es uns gelungen. (aber es brauchte etwas Jonglieren, um alles zusammen spielen zu lassen)

Hoffe, das hilft. Hier ist ein Link zu einigen Informationen, die sich auf 32/64-Bit-Probleme beziehen: http://blog.typemock.com/2008/07/registry-on-windows-64-bit- double-your.html

0
Lior Friedman

Sie können zwei Lösungen unterschiedlich generieren und anschließend zusammenführen! Ich habe dies für VS 2010 getan und es funktioniert. Ich hatte zwei verschiedene Lösungen, die von CMake erstellt wurden, und ich habe sie zusammengeführt

0
tejas