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.
Related
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>
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.
I've been developing a Vb.Net app lately, and I'm trying to make it as lightweight as possible (ie make the binaries as small as possible).
I've done all the trivial stuff, but while browsing the binary with ILDasm, I noticed that it has a My namespace, with a lot of methods, although I don't use any of these in my program. It seems that there are default Get/Set methods for every form, and other methods.
Is there a way to get rid of those?
Or, can you show me a use case for the methods bundled by default in the binary?
PS: I guess it's not going to make a huge difference in binary size: I'm just asking this out of curiosity; why would the compiler bundle useless methods in every binaries? Perhaps I'll learn that these methods are actually used somewhere under the hood.
PPS: Here's a minimal example:
Module Test
Sub Main()
End Sub
End Module
The output is:
Follow these steps:
Click Show All Files in the solution explorer
Open the My Project branch
Open the Settings.settings branch
Open Settings.designer.vb
Edit the My namespace as you wish
There is an additional My sub-namespace called My.Resources which is hiding under the Resources.resx branch.
After furious head-scratching...:
How much is included depends on the value of the _MYTYPE define. It's all documented in MSDN, I failed to find it at first.
In order to remove most of the generated types in the My namespace you will have to set the _MYTYPE define to Empty. To do so you will have to open the .vbproj file in a text editor (using Visual Studio you can do this by first unloading the project and than open it).
Look for the element <MyType> in the first <PropertyGroup> and change its value to Empty:
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C6DC5A64-1E50-48B0-97A5-649D2D323E5E}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>Some.Component</RootNamespace>
<AssemblyName>Some.Component</AssemblyName>
<FileAlignment>512</FileAlignment>
<MyType>Empty</MyType>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<SccProjectName>SAK</SccProjectName>
<SccLocalPath>SAK</SccLocalPath>
<SccAuxPath>SAK</SccAuxPath>
<SccProvider>SAK</SccProvider>
</PropertyGroup>
I have not found a way of removing the InternalXmlHelper that is generated by Visual Studio.
As Clément pointed out it is possible to configure the My namespace using other values of the _MYTYPE define.
This procedure will work for Visual Studio 2012.
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