Hello Gents,

While we were migrating from VS2008 to VS201x I found a problem with harvesting projects containing links to external filesandmore precisely if the link is not in the root level of the project but in a sub-folder.

Following is an example of such project:

<Project ...>
...
  <ItemGroup>
    <Content Include="..\..\FolderOutsideProject\SubFolder\File.ext">
      <Link>Subfolder1\SubFolder2\File.ext</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
...
</Project>

If project is created in VS2008 and uses tools version 3.5 then link's sub-folder is properly recognized and heat generates sub-folders accordinglywhen creating corresponding Component entries. After migration to V201x and tools version 4.0 sub-folders are not taken into account and corresponding Component entries are placed in the root directory.

I tracked the problem down to VSProjectHarvester.cs file and more precisely to VSProjectHarvester.MSBuild40Project.Build() method which does not populate the dictionary of targetOutputs. I also studied the new approach used when building projects against tools 4.0 inside harvester and found a way to populatetargetOutputs so it contains the same data as returned by the old approach used when building against 3.5 target.

Following URL is a pull request with the changes made in 3.8 branch:
https://wix.codeplex.com/SourceControl/network/forks/bdachev/ProjectHarverster/contribution/4702

Please find attached the fix as a patch file if you prefer it that way.

The code below (written in C# and without using reflection) illustrates how to populate targetOutputs:

IDictionary<string, TargetResult> resultsByTarget = buildResult.ResultsByTarget;
            if (resultsByTarget != null)
            {
                foreach (string itemName in targetNames)
                {
                    TargetResult result;
bool hasKey = resultsByTarget.TryGetValue(itemName, out result);
                    if (hasKey)
                    {
                        if (result != null)
                        {
                            ITaskItem[] items = result.Items;
targetOutputs.Add(itemName, items);
                        }
                    }

                    if (!targetOutputs.Contains(itemName))
                    {
targetOutputs.Add(itemName, new List<object>());
                    }
                }
            }

The patch itself is written using reflection as the rest of the code in VSProjectHarverster.cs to avoid references to MSBuild related assemblies.

Hope it will be of some help!
Best regards,
Boris.

PS: The patch also includes a fix for another problem of project harverster related to winforms .resx files
From 9102beadec38ae81873783a637ef1053dfabe9d4 Mon Sep 17 00:00:00 2001
From: Boris Dachev <[email protected]>
Date: Sat, 11 May 2013 22:32:22 +0300
Subject: [PATCH] Fixes in project harvester:

- fix for .resx files problem
- fix for file links
---
 src/ext/VSExtension/wixext/VSProjectHarvester.cs | 48 ++++++++++++++++++++++--
 1 file changed, 44 insertions(+), 4 deletions(-)

diff --git a/src/ext/VSExtension/wixext/VSProjectHarvester.cs 
b/src/ext/VSExtension/wixext/VSProjectHarvester.cs
index 1130f40..c983c49 100644
--- a/src/ext/VSExtension/wixext/VSProjectHarvester.cs
+++ b/src/ext/VSExtension/wixext/VSProjectHarvester.cs
@@ -236,7 +236,17 @@ namespace Microsoft.Tools.WindowsInstallerXml.Extensions
 
             IDictionary buildOutputs = new Hashtable();
 
-            bool buildSuccess = project.Build(projectFile, buildOutputGroups, 
buildOutputs);
+            string pwd = Directory.GetCurrentDirectory();
+            Directory.SetCurrentDirectory(Path.GetDirectoryName(projectFile));
+            bool buildSuccess = false;
+            try
+            {
+                buildSuccess = project.Build(projectFile, buildOutputGroups, 
buildOutputs);
+            }
+            finally
+            {
+                Directory.SetCurrentDirectory(pwd);
+            }
 
             if (!buildSuccess)
             {
@@ -1282,10 +1292,40 @@ namespace Microsoft.Tools.WindowsInstallerXml.Extensions
                     // this.buildManager.EndBuild();
                     this.types.buildManagerType.GetMethod("EndBuild", new 
Type[] { }).Invoke(this.buildManager, null);
 
-                    // fill in empty lists for each target so that heat will 
look at the item group later
-                    foreach (string target in targetNames)
+                    // IDictionary<string, TargetResult> resultsByTarget = 
buildResult.ResultsByTarget;
+                    object resultsByTarget = 
buildResult.GetType().GetProperty("ResultsByTarget").GetValue(buildResult, 
null);
+                    if (resultsByTarget != null)
                     {
-                        targetOutputs.Add(target, new List<object>());
+                        // cache MethodInfo of TryGetValue
+                        var tryGetValue = 
resultsByTarget.GetType().GetMethod("TryGetValue");
+                        object[] prms = new object[2];
+                        // enumerate target names and for each try to get 
items from results of the build
+                        foreach (string itemName in targetNames)
+                        {
+                            // TryGetValue's first parameter is the key set to 
itemName
+                            prms[0] = itemName;
+                            prms[1] = null;
+                            // TargetResult result;
+                            // bool hasKey = 
resultsByTarget.TryGetValue(itemName, out result);
+                            bool hasKey = 
(bool)tryGetValue.Invoke(resultsByTarget, prms);
+                            if (hasKey)
+                            {
+                                // if dictionary has the key then the the 
value should be of TargetResult type
+                                object result = prms[1];
+                                if (result != null)
+                                {
+                                    // ITaskItem[] items = result.Items;
+                                    object items = 
result.GetType().GetProperty("Items").GetValue(result, null);
+                                    targetOutputs.Add(itemName, items);
+                                }
+                            }
+
+                            // fill in empty lists for each target so that 
heat will look at the item group later
+                            if (!targetOutputs.Contains(itemName))
+                            {
+                                targetOutputs.Add(itemName, new 
List<object>());
+                            }
+                        }
                     }
 
                     return buildSucceeded;
-- 
1.8.1.msysgit.1

------------------------------------------------------------------------------
Learn Graph Databases - Download FREE O'Reilly Book
"Graph Databases" is the definitive new guide to graph databases and 
their applications. This 200-page book is written by three acclaimed 
leaders in the field. The early access version is available now. 
Download your free book today! http://p.sf.net/sfu/neotech_d2d_may
_______________________________________________
WiX-devs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/wix-devs

Reply via email to