I have found some free compilers online, but I can't figure out how to add external references to any of them. Is there a special Imports statement I can use, so that VB.NET will go looking for a third party .dll in a certain relative path, so that I don't have to add references through Visual Studio? The specific reference I am trying to add first is the DI interop for SAP B1, but this probably isn't going to be the only one I will need to add.
I know that I can add a /reference to add a reference in a command line compilation, if I am using Microsoft's command line compiler, but that seems to be against the license for my client now. I gather the old Express 2010 versions could compile and add references without revenue restrictions, but I am looking for syntax on how to tell a compiler to add a reference, not a software recommendation (since I don't think I can still get those Express editions).
The answer is as #Jaxedin and #T.S. said in comments to the question, but I wasn't aware of the existence of the MSBuild software.
I had read in various places in reference to MSBuild comments like "And keep in mind that for now, you’ll need to have Visual Studio 2015 installed in order to build the first time." (MSDN), and just took them for face value.
Being able to put the references inside an XML .vbproj is much easier than I had been imagining. Something like:
<ItemGroup>
<Reference Include="System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<Name>System</Name>
<SpecificVersion>True</SpecificVersion>
<HintPath>...\systemDir\System.dll</HintPath>
<ReferenceOutputAssembly>True</ReferenceOutputAssembly>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Reference>
</ItemGroup>
Related
Related: Conditionally use 32/64 bit reference when building in Visual Studio
Normally when you add vb.net projects as reference in the same solution there is a reference added with a hint location. now in C# as far as i remember it adds it based on architecture. Why not in Vb.net or am i just doing it wrong. Check the related question.
<Reference Include="MyComAssembly.Interop">
<HintPath>..\..\lib\x86\MyComAssembly.Interop.dll</HintPath>
</Reference>
<ItemGroup Condition=" '$(Platform)' == 'x64' ">
<Reference Include="MyComAssembly.Interop">
<HintPath>..\..\lib\x64\MyComAssembly.Interop.dll</HintPath>
</Reference>
To clarify i do get the entry but its not architecture based by default. The related question does talk about manually editing the file but I am trying to understand why its not happening automatically for VB.net compared to C#. Is there any open feature request as well.
Edit on 6/6/2017
for Vb.net it shows the references correctly as explained in first response, but why doesn't a COM reference work in the same way.
I am posting this as answer, because I need to show some code here
You said:
Normally when you add vb.net projects as reference in the same solution there is a reference added with a hint location
Answer:
No. Project reference is created as following
<ProjectReference Include="..\..\..\MyProject\MyProject.csproj">
<Project>{7316c328-7716-4b5c-b736-f5811c764158}</Project>
<Name>MyProject</Name>
</ProjectReference>
Your XML shows DLL reference. If you reference from DLL, you get the hint.
And the ItemGroupcondition is not added by default, not in C#, not in VB. This is something you do manually. I am telling you this as build master who constantly configures projects and solutions.
I often see the situation when assembly references have wrong HintPath and this can cause strange random failures.
For example, you have wrong HintPath, but you have a corresponding assembly in your GAC.
It will mean that the project will compile ok on your machine but will fail on others.
In my case it is vise versa, there is a library in GAC even on CI server, so this problem will not detectable by continuous integration.
I am looking for something like custom MSBuild task which will validate all HintPaths and cause build failure if any of them are wrong.
If you want to fail the build if the hint path is invalid, why not just reference something explicitly? This is SOP at my company due to having lots of versions of the same library.
For example:
<Reference Include="C:\Path\To\Library\MyReference.dll">
<Private>False</Private>
</Reference>
Or, if you want to reference libraries based on some path dynamically, you can set some msbuild property, say, "ExternalLibs" that points to your libraries folder (if you keep libs in source control, etc). Then you can set that property via the command line (when you call msbuild) or give it some default value that each user can override in their .user files, for example.
<Reference Include="$(ExternalLibs)\MyReference.dll">
<Private>False</Private>
</Reference>
This solution is pretty flexible.
I have a C# project which is built in a few different configurations. Some of the source files should be always included, and some only in certain configurations. So far I've been doing this with #if ... #endif around the entire files, but I was hoping to create a small extension to do this a nicer way.
I've created an extension that adds an item to files' context menus, but I can't find any way to set the Condition attribute on the item node in the project file.
I've looked at the Properties collection of the EnvDTE.ProjectItem interface, but can't see anything useful there (except BuildAction... I'll come back to that).
Then I tried getting an IVsBuildPropertyStorage on the item and calling SetItemAttribute(). This does add information to the project file, but as a child element like this:
<ItemGroup>
<Compile Include="Program.cs">
<Condition>%27%24%28Configuration%29%27==%27Debug%27</Condition>
</Compile>
</ItemGroup>
when what I was trying to achieve was:
<ItemGroup>
<Compile Include="Program.cs" Condition="'$(Configuration)'=='Debug'" />
</ItemGroup>
There's also an IVsBuildPropertyStorage.SetPropertyValue() but that adds a similar child element to a PropertyGroup section near the top, not to the item node.
I've looked at 'Project Subtypes/Flavors', but that looks like it's just going to get me another IVsBuildPropertyStorage, which doesn't seem to be useful. They do look capable of a lot of complex things, but documentation on the subject appears to be minimal and vague.
I've seen some posts describing how to use the MSBuild assemblies to directly load and manipulate the project file, but I'm not sure when is safe to do that without confusing Visual Studio and potentially losing changes, since VS prompts to reload when it detects changes to the project file.
As a last idea, I thought about manipulating the BuildAction property between Compile and None, but that sounds like it could be a lot of work for my extension to maintain correctly, keeping it in sync with every time the user switches configurations in the IDE for example.
Is there anyone with any experience with this kind of thing that has any advice to offer me, or should I give up hope and stick with manually adding #if directives everywhere?
You may like to explore the MSBuild option you mentioned.
You don't actually have to load the MSBuild project from file, because Visual Studio gives you a way of accessing the MSBuild project directly, i.e.:
string projectPath = projectItem.ContainingProject.FullName;
MsBuildProject project = ProjectCollection.GlobalProjectCollection.GetLoadedProjects(projectPath);
var compileItems = project.GetItems("Compile");
From there you can locate your specific items and potentially add the condition attribute, though I haven't tried this step myself (if this doesn't work, you might have to try modifying the project elements under the project.Xml property instead).
You can then call project.Save(), which shouldn't trigger the "Reload project?" dialog because of the way the MsBuild project instance is linked to the Visual Studio project hierarchy.
However, you may like to force Visual Studio to reload the project anyway, because if you switch build configurations (e.g. between Debug and Release), the MSBuild engine may not re-evaluate your item conditions during build. The code to do this programmatically can be found here:
How do I programmatically refresh/reload a VS project after modifying the underlying file?
Unfortunately I never got the time to persue the original goal of creating an extension for doing this, however I did achieve what I needed using the suggestion by lex-li: using separate project files per configuration.
Since the project files can all reside in the same directory, it's easy to simply use the 'Include/Exclude from project' context menu item in the solution explorer to choose which files are included. There's also no need for file linking this way, which I'd tried before and found very time-consuming to manage.
Partial Methods are also worth looking at, if you have similar needs. They allow you to define the signature of a method in one place, but optionally implement it elsewhere. If you don't implement it, no call is generated by the compiler.
With respect to the original idea of the extension, I suspect the answer by Daniel Nolan was heading in the right direction, but unfortunately I didn't get to try it out.
In the spirit of this question by Si here: WiX tricks and tips. I am trying to determine the best way to get create wix fragments based on a directories. File harvesting, so to speak. For example under the bin\release folder I could have many different folders plus files that I want to capture very easily in fragments. I have been doing this by typing them or using wixedit.
Please note I haven't tried anything just done the reasearch here:
A)I read a little bit on heat.(http://installing.blogspot.com/2006/04/heatexe-making-setup-easier.html) I am not sure though about running it from msbuild?
B)I found this blog article from Newagesolution which discusses using t4 script: http://blog.newagesolution.net/2008/06/how-to-use-msbuild-and-wix-to-msi.html
I would like to know what others are doing to solve this.
Regards, Brian
Ok, Daniel I definately agree with using heat, but I think Rob pointed me in the right direction for what I ended up using.
What I ended up using was HeatDirectory.(Please note, I do not plan on doing patching. If you want patching, you may want to look at another solution, but heat/heat directory can work for patching.) Unfortunately, Rob's answer was quite limited, so I wouldn't say that he really answered my question. Just pointed me in the right direction. Thanks to both Rob and Daniel for your help.
Therefore, I came back and answered this question myself.
Hurdles...
Hurdle 1
I ran into is there is nearly no documentation on the web for how to implement heat tasks/heat directory(Heat wrapped in msbuild) from within visual studio. Please note that the wrapper to run from msbuild appears to be pretty new and I disclaim to use at your own risk, etc. Because of the lack of documentation, I sent an email to the wix user list. I received help from Brian Rogers. Thanks Brian, this solved everything for me. Take a look at his great blog entry here for a better understand how heat is going to help you automate: http://icumove.spaces.live.com/blog/cns!FB93073C6534B681!461.entry
Hurdle 2
After working with heat, I found out that I was not using components the recommended way, but I had to piece together all the reasoning. I think many people will run into this in the beginning of using Wix if you don't have prior knowledge of windows installer. Therefore I recommend some reading:
Make sure you read component rules as well if you are a novice like I was with Windows Installer.Component rules from MS: http://msdn.microsoft.com/en-us/library/aa370561.aspx. Read these from Rob Mensching for a better understanding of components: http://robmensching.com/blog/posts/2003/10/4/Windows-Installer-Components-Introduction
http://robmensching.com/blog/posts/2003/10/18/Component-Rules-101
For Extra Reading on Windows installer check these rules from the windows installer team(Rule 16: Follow Component Rules):
http://blogs.msdn.com/windows_installer_team/archive/2006/05/12/595950.aspx
Hurdle 3
You must decide whether or not you want to do patching of your files or upgrade everytime you install a new version.
I fortunately do not need to do patching, therefore for every upgrade I will just uninstall the previous version like this: How to implement WiX installer upgrade?.
This simplifies things greatly. When patching you are going to need full control over things. Something that is more difficult when you want automation/automatic building for by many developers that do not know anything about wix other than wix builds msi fields. It seems that this will work with using heat, but I am uncertain.
Hurdle 4
For me it took a little time to figure out why the include file with my preprocessor variables was not working. I finally figured it out. You must include the file in your .wxs file like this:
See here for more details:
Include a text file content into a WiX script
http://wix.sourceforge.net/manual-wix2/preprocessor.htm
Hurdle 5
Since I am using major upgrades with mix and I wanted to hook in subversion into my product number. This I thought would be quite simple and it is if you know how to do it. I had trouble here and had to get help for this as well.
Hurdle 6
With heat updating the files based on a bin folder everything works quite well. Well almost automatic, if there are any conflicts in dll references, etc then files will not be included in the installer and therefore things might not run properly. You need to have a testing process in place so as to test your program after installing. This can be critical if you miss a dll. I would also recommended that you keep track of the program's used dlls and compare against the msi file.
Now for the solution using HeatDirectory(from the help of Brian Rogers(wix team)):
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == ''">Debug</Configuration>
<OutputName>msbuild.heatfile</OutputName>
<OutputType>Package</OutputType>
<WixToolPath>..\..\YourHeatDir</WixToolPath>
<WixToolPath>$(WixToolPath)</WixToolPath>
<Cultures>en-us</Cultures>
<LinkerBaseInputPaths>..\..\data\HeatDir</LinkerBaseInputPaths>
</PropertyGroup>
<ItemGroup>
<Compile Include="product.wxs" />
<Compile Include="TestDir.wxs" />
</ItemGroup>
<Import Project="$(WixToolPath)\Wix.targets" />
<UsingTask TaskName="HeatDirectory"
AssemblyFile="$(WixToolPath)WixUtilExtension.dll" />
<Target Name="BeforeBuild">
<HeatDirectory
Directory="..\..\data\HeatDir"
DirectoryRefId="DataDir"
OutputFile="TestDir.wxs"
AutogenerateGuids="true"
ToolPath="$(WixToolPath)" />
</Target>
This needs to be pasted into your project file and appropriate settings/pathing needs to be changed. What this will do is take all the files in the path you specify
and create a TestDir.wxs file which you then can reference by component group. There are several Heatdirectory options see you need to see the heat sourcecode for details.
Just for reference: I found this post on stackoverflow after I posted my question: How to add a whole directory or project output to WiX package
Also for reference I just saw this article here: Harvesting a .csproj with heat.exe in Visual Studio 2008 and WiX(v3). and again this can be done using heat tasks instead.
Both discuss using third party tools. One called Mallow and another called Paraffin. I think paraffin looks supported and can do pretty much what heat does.
With a few additions: See here for details: http://www.wintellect.com/cs/blogs/jrobbins/archive/2007/10/18/wix-hints-for-new-users-part-1-of-3.aspx
Anyways hope this helps others.
The new HeatTasks might work very well for you here. They can pull project output groups from other projects in Visual Studio. It does much better in the latest build than older builds, so be sure to pick up a weekly http://wixtoolset.org/releases/.
For what it's worth, we are, in fact, using heat.exe from msbuild. If you're as picky as I am, the output of heat is probably not exactly what you want, but this is easy to rectify with an XSL transformation (I believe heat.exe has a command-line parameter expressly for this purpose).
When I add a reference to Microsoft.Office.Interop.Excel on my computer, Visual Studio adds this to the project file:
<COMReference Include="Excel">
<Guid>{00020813-0000-0000-C000-000000000046}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>5</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>False</Isolated>
</COMReference>
There is another developer on the team who gets errors and needs to add a DLL file to the project called Interop.Excel.dll, which replaces the code above with this in the project file:
<Reference Include="Interop.Excel, Version=1.5.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>My Project\Interop.Excel.dll</HintPath>
</Reference>
This does work on my computer.
Could you please explain the differences between the two methods, which is best, and how to get the first one working on other computers?
I don't see a problem with your approach either.
Typically VS will generate an interop assembly for COM components automatically when you add a reference to the component. However, when you add a reference to one of the Office components (XP or any later version), a reference to the pregenerated (and optimized) primary interop assembly from Microsoft is added as in your first example. The line
<WrapperTool>primary</WrapperTool>
means that this PIA is used.
If you correctly added the PIA reference the CopyLocal property of this reference should be set to false and the Path property should be something like
C:\WINDOWS\assembly\GAC\Microsoft.Office.Interop.Excel\12.0.0.0__71e9bce111e9429c\Microsoft.Office.Interop.Excel.dll
You will find some more details on interop assemblies in this MSDN article.
To get the first method working it is necessary that the Office Primary Interop Assemblies (PIAs) are installed on the machine. There is a redistributable version available from Microsoft:
Office 2003 PIAs
Office 2007 PIAs
AFAIK, these PIAs only get installed by the Office setup when the .NET Framework has already been installed, that's why there is a separate redistributable for the PIAs.
Note: Make sure that you reference the version of Office that you are targeting. When targeting several versions of Office, you might get some problems however. A solution in that case might be late binding (if performance is not an issue).
I've used Excel automation way more than I would like to admitt, and I have never referenced Interop.Excel.dll. I've always referenced the former. Why is he referencing that, and what errors does he get?
Are you guys referencing the same version of excel (5.0 verses 11.0)? Do you guys have the exact same version of office, service pakcs and all? This could be the differance.
I found the cleanest way to use it, this also allows for multiple versions of the interop, is to create a shared bin\Office Interop\11 or 12\Microsoft.Office.Interop.Excel.dll\ and refeferenced them from the project, works a treat for different version