2013-06-13 9 views
9

In einem Versuch zur Konsolidierung Projekteinstellungen in Eigenschaftsfenster sowohl für C++ und C# -Projekten, die folgenden Eigenschaftsfenster aufgebaut:Warum verursacht das Ändern von Projektausgabedateien die Ursache: IOException wurde nicht behandelt "Die Ressource 'app.xaml' kann nicht gefunden werden."

<?xml version="1.0" encoding="utf-8"?> 
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <!-- 
     Trying to support both C++ and C# projects by introducing derived 
     properties and setting the appropriate output properties. 
    --> 
    <PropertyGroup Label="UserMacros"> 
    <ProjectOrAssemblyName Condition="'$(AssemblyName)'==''">$(ProjectName)</ProjectOrAssemblyName> 
    <ProjectOrAssemblyName Condition="'$(ProjectName)'==''">$(AssemblyName)</ProjectOrAssemblyName> 
    <ShortPlatform Condition="'$(Platform)'=='Win32'">x86</ShortPlatform> 
    <ShortPlatform Condition="'$(Platform)'=='x86'">x86</ShortPlatform> 
    <ShortPlatform Condition="'$(Platform)'=='x64'">x64</ShortPlatform> 
    <ShortPlatform Condition="'$(Platform)'=='AnyCPU'">AnyCPU</ShortPlatform> 
    </PropertyGroup> 
    <PropertyGroup> 
    <OutputPath>$(OutputRelativePath)/$(ProjectOrAssemblyName)_$(ShortPlatform)_$(Configuration)/</OutputPath>   
    <BaseIntermediateOutputPath>$(OutputRelativePath)/Obj_Exe/$(ProjectOrAssemblyName)_$(ShortPlatform)</BaseIntermediateOutputPath> 
    <IntermediateOutputPath>$(BaseIntermediateOutputPath)_$(Configuration)/</IntermediateOutputPath> 
    <IntDir>$(IntermediateOutputPath)</IntDir> 
    <OutDir>$(OutputPath)</OutDir> 
    </PropertyGroup> 
</Project> 

Blatt wird diese Eigenschaft aller Ausgaben an einen separaten Ort OutputRelativePath (definiert bauen bewegen in separaten Eigenschaftenblatt oder direkt in Projektdatei) außerhalb Verzeichnisse, die Quellcode für einfachere Säuberung usw. enthalten. Jedoch, nach dem Einrichten und bauen funktioniert gut und alle Komponententests funktionieren gut, es war klar, dass ein ausführbares WPF-Projekt nicht in Ordnung war, seit dem Ausführen der Anwendung mit oben genannten Eigenschaftenblatt Ergebnisse in der berüchtigten:

IOException was unhandled "Cannot locate resource 'app.xaml'." 

Warum führt das Ändern der Ausgangspfade zu diesem Fehler? Und wie kann festgestellt werden, dass die Ursache Projekt-Build-Output-Pfade sind? Kann dies im generierten Code gesehen werden? Ich konnte es nicht finden? Und ist das nicht ein Fehler?

HINWEIS: Mit den folgenden Eigenschaftsfenster funktioniert, aber nur, wenn IntermediateOutputPath enthält BaseIntermediateOutputPath.

<?xml version="1.0" encoding="utf-8"?> 
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
    <PropertyGroup> 
    <OutputPath>$(OutputRelativePath)/$(AssemblyName)_$(Platform)_$(Configuration)</OutputPath> 
    <BaseIntermediateOutputPath>$(OutputRelativePath)/Obj_Exe/$(AssemblyName)_$(Platform)</BaseIntermediateOutputPath> 
    <IntermediateOutputPath>$(BaseIntermediateOutputPath)_$(Configuration)</IntermediateOutputPath> 
    </PropertyGroup> 
</Project> 

So scheint es, dass irgendwie erwartet wird, dass Ausgabe Pfade die AssemblyName Eigenschaften oder ähnliches enthalten.

UPDATE FÜR XAML-STYLES IN EINER ANDEREN MONTAGE: Das gleiche gilt für Xaml ResourceDictionary, wenn diese - z. Brushes.xaml - befinden sich in einer anderen Baugruppe und diese Anordnung hat den OutputPath auch geändert, dies führt auch eine Ausnahme:

XamlParseException was unhandled for set property Source 
with InnerException "Cannot locate resource 'Brushes.xaml'" 

Also alles in allem scheint es Ausgabeort ändert den XAML-Ressource-Namen, so dass dies nicht entdeckt werden kann, Laufzeit, irgendwie. Das Seltsame ist, ist es kein Problem beim Entwurf ist ...


UPDATE: Minimale Schritte, um die Ausnahme zu reproduzieren:

Öffnen Sie Visual Studio 2013

neue C# -Projekt WPF-Anwendung erstellen z.B. XamlIntermediateOutputPathBug

Unload Projekt

bearbeiten Projektdatei

Nach dem ersten Property neues Property einfügen:

<PropertyGroup> 
    <OutputRelativePath>$(ProjectDir)..\Build</OutputRelativePath> 
    <OutputPath>$(OutputRelativePath)/$(AssemblyName)_$(Platform)_$(Configuration)/</OutputPath> 
    <BaseIntermediateOutputPath>$(OutputRelativePath)/Obj_Exe/$(AssemblyName)_$(Platform)</BaseIntermediateOutputPath> 
    <IntermediateOutputPath>$(BaseIntermediateOutputPath)_$(Configuration)/</IntermediateOutputPath> 
    <IntDir>$(IntermediateOutputPath)</IntDir> 
    <OutDir>$(OutputPath)</OutDir> 
</PropertyGroup> 

OutputPath Eigenschaften löschen PropertyGroups in verbleibenden z.B.

<OutputPath>bin\Debug\</OutputPath> 

und:

<OutputPath>bin\Release\</OutputPath> 

Dies sollte dann eine IOException auf Start für mainwindow.xaml werfen.Dies ist aufgrund der $(AssemblyName).g.resources eingebettete Ressource der folgenden Namen gegeben:

.mresource public 'Build/Obj_Exe/XamlIntermediateOutputPathBug_AnyCPU_Debug/XamlIntermediateOutputPathBug.g.resources' as Build_Obj_Exe_XamlIntermediateOutputPathBug_AnyCPU_Debug_XamlIntermediateOutputPathBug.g.resources 
{ 
    // Offset: 0x00000000 Length: 0x000003BC 
} 
.mresource public 'Build/Obj_Exe/XamlIntermediateOutputPathBug_AnyCPU_Debug/XamlIntermediateOutputPathBug.Properties.Resources.resources' as Build_Obj_Exe_XamlIntermediateOutputPathBug_AnyCPU_Debug_XamlIntermediateOutputPathBug.Properties.Resources.resources 
{ 
    // Offset: 0x000003C0 Length: 0x000000B4 
} 

wie bei ildasm.exe und Öffnen der MANIFEST für den Zusammenbau gesehen werden kann. Wie man auch sieht, erhalten die normalen Ressourcen auch einen falschen Namen mit dem vorangestellten Ausgabepfad. Dies kann jedoch durch Setzen der LogicalName in der Projektdatei für diese Ressource behoben werden (siehe MissingManifestResourceException when running tests after building with MSBuild (.mresource has path in manifest)). Dies scheint nicht für XAML-Ressourcen möglich zu sein ...

bei der Konfiguration sah Nachdem ich, dass ich am Ende der OutputPath und IntermediateOutputPath verwende / bemerkt, entfernt diese es scheint zu funktionieren, siehe unten:

<PropertyGroup> 
    <OutputRelativePath>$(ProjectDir)..\Build</OutputRelativePath> 
    <OutputPath>$(OutputRelativePath)/$(AssemblyName)_$(Platform)_$(Configuration)</OutputPath> 
    <BaseIntermediateOutputPath>$(OutputRelativePath)/Obj_Exe/$(AssemblyName)_$(Platform)</BaseIntermediateOutputPath> 
    <IntermediateOutputPath>$(BaseIntermediateOutputPath)_$(Configuration)</IntermediateOutputPath> 
    <IntDir>$(IntermediateOutputPath)/</IntDir> 
    <OutDir>$(OutputPath)/</OutDir> 
</PropertyGroup> 

Ich finde das ziemlich neugierig ... jede Einsicht, warum das der Fall wäre oder ob das tatsächlich wahr ist, wird geschätzt. Beachten Sie, dass C++ IntDir und OutDir stattdessen einen nachgestellten Backslash haben müssen, sonst erhalten Sie Warnungen darüber.

+0

Können Sie mit Protokollierung zu Diagnose erstellen, um zu sehen, ob Sie weitere Informationen erhalten, wo die IOException und XamlParseException auftreten? – Nicodemeus

Antwort

4

die Ausführlichkeit MSBuild Ausgang Einstellung mit „Diagnose“ ergab, schnell die Ursache des Problems:

1> (TaskId:21) 
1> Microsoft (R) Build Task 'ResourcesGenerator' Version '4.0.30319.33440 built by: FX45W81RTMREL'. (TaskId:21) 
1> Copyright (C) Microsoft Corporation 2005. All rights reserved. (TaskId:21) 
1> 
1> (TaskId:21) 
1> Generating .resources file: '..\Build/Obj_Exe/WpfApplication8_AnyCPU_Debug/WpfApplication8.g.resources'... (TaskId:21) 
1> Reading Resource file: 'C:\Users\hpass_000\Projects\Build\Obj_Exe\WpfApplication8_AnyCPU_Debug\MainWindow.baml'... (TaskId:21) 
1> Resource ID is 'mainwindow.baml'. (TaskId:21) 
1> Generated .resources file: '..\Build/Obj_Exe/WpfApplication8_AnyCPU_Debug/WpfApplication8.g.resources'. 

Beachten Sie die Mischung aus Vorwärts- und Rückwärtsschrägstriche in den Pfadnamen. Windows selbst weiß, wie man Schrägstriche in Pfadnamen gut verarbeitet. Aber diese Fähigkeit fehlt oft in anderer Software, sie fehlt in der Ressourcengenerator-Aufgabe. Bei Verwendung eines umgekehrten Schrägstrichs als Pfadtrennzeichen ist ein Schrägstrich in einem Ressourcennamen gültig. Fix:

<OutputPath>$(OutputRelativePath)\$(AssemblyName)_$(Platform)_$(Configuration)\</OutputPath> 
<BaseIntermediateOutputPath>$(OutputRelativePath)\Obj_Exe\$(AssemblyName)_$(Platform)</BaseIntermediateOutputPath> 
<IntermediateOutputPath>$(BaseIntermediateOutputPath)_$(Configuration)\</IntermediateOutputPath> 

Mit anderen Worten, ich ersetzt einfach / mit \. Welches löste das Problem.

1

WinFX- und Xaml-Ziele führen einige Hacks/magic hinter den Kulissen aus, wenn der Xaml auf einen Typ verweist, der sich im aktuellen Projekt befindet. Während dieser Erstellungsaufgabe wird wpf.csproj nach tempfilename.tmp_proj kopiert, mehrere Knoten, die sich auf Assemblyverweise beziehen, werden gekürzt, und die Datei wird in den IntermediateOutputPath kompiliert. Dadurch kann der Xaml-Compiler auf Typen innerhalb der temporären Assembly verweisen.

Verwandte Themen