2013-06-13 55 views
9

在試圖鞏固項目設置成用於C++和C#項目屬性表,以下屬性表構建:爲什麼修改項目輸出目錄會導致:IOException未處理「無法找到資源'app.xaml'。」

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

該屬性表將移動所有輸出建立一個單獨的地點OutputRelativePath(定義在單獨的屬性表中或直接在項目文件中)包含源代碼的目錄之外,以便於清理等。但是,設置完成並且構建工作正常並且所有單元測試都正常工作後,顯然WPF可執行項目並不好,因爲使用以上屬性表運行應用程序導致臭名昭着:

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

爲什麼更改輸出路徑會導致此錯誤?如何確定原因是項目構建輸出路徑?這可以在生成的代碼中看到嗎?我找不到?這不是一個錯誤?

注:使用下面的屬性表的作品,但只有當IntermediateOutputPath包含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> 

因此,看起來,預計輸出路徑包含AssemblyName屬性或類似。

XAML樣式在另一個彙編中的更新:這同樣適用於xaml ResourceDictionary,如果這些是 - 例如Brushes.xaml - 位於另一個組件,該組合已經改變了OutputPath也,這也將引發異常:

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

因此,所有的一切似乎輸出位置改變XAML資源名稱,以便這些不能被發現不知何故,運行時。奇怪的是它是不是在設計時的一個問題...


UPDATE:最少的步驟重現例外:

打開Visual Studio 2013

創建新的C#項目WPF應用程序如XamlIntermediateOutputPathBug

卸載項目

編輯項目文件

第一的PropertyGroup後插入新的PropertyGroup爲:

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

在例如剩餘PropertyGroups刪除OutputPath性質

<OutputPath>bin\Debug\</OutputPath> 

和:

<OutputPath>bin\Release\</OutputPath> 

這應該再扔上啓動IOExceptionmainwindow.xaml。這是由於$(AssemblyName).g.resources嵌入資源給出以下名稱:

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

如可以用ildasm.exe可以看出,爲裝配打開MANIFEST。正如也可以看到的那樣,普通資源的輸出路徑前綴也是錯誤的。但是,可以通過在此資源的項目文件中設置LogicalName來解決此問題(請參閱MissingManifestResourceException when running tests after building with MSBuild (.mresource has path in manifest))。這似乎並不可能爲XAML資源...

說完看着我發現我使用/OutputPathIntermediateOutputPath的端的配置,除去這些似乎工作,見下圖:

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

我覺得這很奇怪......任何洞察,爲什麼這將是這種情況,或者如果這是事實真的讚賞。請注意,C++ IntDirOutDir必須具有尾部反斜槓,否則您將收到有關此問題的警告。


+0

您可以使用設置爲診斷的日誌記錄進行構建,以查看是否在IOException和XamlParseException發生時獲取更多信息? – Nicodemeus

回答

4

設置的MSBuild輸出詳細程度爲「診斷」很快揭示了問題的根源:

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

注意向前和向後的斜槓的路徑名的組合。 Windows本身知道如何正確處理路徑名稱中的正斜槓。但是這種功能在其他軟件中經常是缺乏的,它缺少資源生成器的任務。這需要一個真正的反斜槓作爲路徑分隔符,正斜槓在資源名稱中是有效的。修復:

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

換句話說,我簡單地更換/\。解決了這個問題。

1

當Xaml引用位於當前項目中的類型時,WinFX和Xaml目標執行一些幕後黑客/魔術。在此構建任務期間,將wpf.csproj複製到tempfilename.tmp_proj,修剪與組件引用相關的幾個節點,並將該文件編譯到IntermediateOutputPath中。這允許Xaml編譯器引用臨時程序集中的類型。

相關問題